home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / modem / ic201c.zip / SCRTUTOR.DOC < prev    next >
Text File  |  1994-06-06  |  241KB  |  4,805 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.                                   Intellicomm (TM)
  7.                                        v2.01
  8.        Copyright (C) 1991-1994 Liberation Enterprises.  All rights reserved.
  9.        ---------------------------------------------------------------------
  10.                         INTELLICOMM SCRIPT LANGUAGE TUTORIAL
  11.        ---------------------------------------------------------------------
  12.  
  13.  
  14.                                  TABLE OF CONTENTS
  15.  
  16.  
  17.      1.  INTRODUCTION  . . . . . . . . . . . . . . . . . . . . . . . . . .   1
  18.          1.1  What are Scripts?  . . . . . . . . . . . . . . . . . . . . .   1
  19.          1.2  Why Should I Bother With Scripts?  . . . . . . . . . . . . .   1
  20.          1.3  Is This Going to Take HOURS? . . . . . . . . . . . . . . . .   2
  21.          1.4  Script Learn Mode  . . . . . . . . . . . . . . . . . . . . .   2
  22.          1.5  How Do I Create a Script?  . . . . . . . . . . . . . . . . .   3
  23.          1.6  Icom's Internal Editor vs. an External Editor  . . . . . . .   4
  24.          1.7  Stopping Scripts . . . . . . . . . . . . . . . . . . . . . .   4
  25.          1.8  Creating and Running Your First Script . . . . . . . . . . .   5
  26.          1.9  A More Exciting Example  . . . . . . . . . . . . . . . . . .   6
  27.          1.10  Other Ways of Running Scripts . . . . . . . . . . . . . . .   8
  28.                1.10.1  Running Script from BIFs (8); 1.10.2  Running
  29.                Scripts from Jobs (8); 1.10.3  Running Scripts from DOS
  30.                (9); 1.10.4  Running Scripts from Scripts (9); 1.10.5 
  31.                Running Scripts from the Script Manager (9); 1.10.6 
  32.                Running Scripts via Function Keys (10)
  33.          1.11  It Can't be That Simple, Can It?  . . . . . . . . . . . .    10
  34.          1.12  Variable Overview . . . . . . . . . . . . . . . . . . . .    15
  35.          1.13  A Word on Formatting  . . . . . . . . . . . . . . . . . .    18
  36.          1.14  Why the Double Quotes ""? . . . . . . . . . . . . . . . .    19
  37.          1.15  Specifying Control Characters . . . . . . . . . . . . . .    19
  38.          1.16  Tildes  . . . . . . . . . . . . . . . . . . . . . . . . .    20
  39.          1.17  Specifying Numbers  . . . . . . . . . . . . . . . . . . .    20
  40.          1.18  Numeric Limits  . . . . . . . . . . . . . . . . . . . . .    21
  41.          1.19  Compound Statements . . . . . . . . . . . . . . . . . . .    21
  42.          1.20  Where To Go From Here . . . . . . . . . . . . . . . . . .    23
  43.          1.21  The Secret to Success . . . . . . . . . . . . . . . . . .    24
  44.  
  45.      2.  WHAT HAPPENS WHEN A SCRIPT ENDS?  . . . . . . . . . . . . . . .    26
  46.          2.1  EXIT and RETURN Error codes  . . . . . . . . . . . . . . .    27
  47.          2.2  Using the HANGUP Command for Error-Recovery  . . . . . . .    28
  48.  
  49.      3.  INTRODUCTION TO SUBROUTINES (GOSUB) . . . . . . . . . . . . . .    28
  50.          3.1  When to use a Subroutine . . . . . . . . . . . . . . . . .    28
  51.          3.2  Writing a Subroutine . . . . . . . . . . . . . . . . . . .    29
  52.          3.3  GOSUB In Detail  . . . . . . . . . . . . . . . . . . . . .    30
  53.          3.4  Creating a Subroutine Template . . . . . . . . . . . . . .    31
  54.  
  55.      4.  SCRIPT VARIABLES IN DETAIL  . . . . . . . . . . . . . . . . . .    32
  56.          4.1  Why Would I Want to Use Variables? . . . . . . . . . . . .    32
  57.          4.2  Where you CAN'T use Variables  . . . . . . . . . . . . . .    32
  58.          4.3  User-Defined Variables . . . . . . . . . . . . . . . . . .    32
  59.          4.4  User-Defined Variable Rules  . . . . . . . . . . . . . . .    33
  60.          4.5  Why All the Rules? . . . . . . . . . . . . . . . . . . . .    35
  61.          4.6  Using Variables  . . . . . . . . . . . . . . . . . . . . .    36
  62.          4.7  The Life of a Variable . . . . . . . . . . . . . . . . . .    37
  63.          4.8  Global Variables . . . . . . . . . . . . . . . . . . . . .    38
  64.  
  65.  
  66.  
  67.  
  68.      Intellicomm v2.01              SCRTUTOR.DOC                             ii
  69.      
  70.      
  71.  
  72.          4.9  Using Global Variables . . . . . . . . . . . . . . . . . .    40
  73.          4.10  Passing Parameters to Scripts . . . . . . . . . . . . . .    41
  74.          4.11  Checking the Number of Passed Parameters  . . . . . . . .    43
  75.          4.12  System Variables  . . . . . . . . . . . . . . . . . . . .    44
  76.          4.13  BIF Variables . . . . . . . . . . . . . . . . . . . . . .    45
  77.          4.14  Main Setup and Environment Variables  . . . . . . . . . .    45
  78.          4.15  Environment Variables . . . . . . . . . . . . . . . . . .    45
  79.  
  80.      5.  PERMANENT VARIABLES: INTRODUCTION TO FILE INPUT/OUTPUT  . . . .    46
  81.          5.1  FOPEN 'Modes'  . . . . . . . . . . . . . . . . . . . . . .    47
  82.          5.2  The File Handle  . . . . . . . . . . . . . . . . . . . . .    48
  83.          5.3  Testing for End-of-File    . . . . . . . . . . . . . . . .    53
  84.          5.4  How to store settings on-disk  . . . . . . . . . . . . . .    53
  85.          5.5  Moving the File Pointer (Advanced Use Only)  . . . . . . .    54
  86.          5.6  Opening a File for Reading AND Writing (Advanced use only)    57
  87.          5.7  Upating an Old Data File . . . . . . . . . . . . . . . . .    59
  88.  
  89.      6.  INTRODUCTION TO DATABASE COMMANDS (FILE TAGGER CATALOGS)  . . .    62
  90.          6.1  Why would I want to use the catalog-oriented commands? . .    62
  91.          6.2  What is a Database?  . . . . . . . . . . . . . . . . . . .    62
  92.          6.3  Indexes  . . . . . . . . . . . . . . . . . . . . . . . . .    63
  93.          6.4  Using File Tagger Indexes  . . . . . . . . . . . . . . . .    64
  94.          6.5  How this all applies to Scripts  . . . . . . . . . . . . .    65
  95.          6.6  The View Date  . . . . . . . . . . . . . . . . . . . . . .    70
  96.          6.7  Getting Around in a Catalog  . . . . . . . . . . . . . . .    71
  97.          6.8  Getting the Total Number of Records  . . . . . . . . . . .    72
  98.          6.9  The View Date and Tagged/Noted Files . . . . . . . . . . .    73
  99.  
  100.      7.  USING THE SCRIPT DEBUGGER . . . . . . . . . . . . . . . . . . .    74
  101.          7.1  What are BUGS, and What is a DEBUGGER? . . . . . . . . . .    74
  102.          7.2  Using the Debugger . . . . . . . . . . . . . . . . . . . .    75
  103.          7.3  Checking the Contents of a Single Variable . . . . . . . .    77
  104.          7.4  Debug Hotkeys  . . . . . . . . . . . . . . . . . . . . . .    78
  105.  
  106.  
  107.  
  108.  
  109.      Intellicomm v2.01              SCRTUTOR.DOC                              1
  110.      
  111.      
  112.  
  113.                                   1.  INTRODUCTION
  114.  
  115.  
  116.      1.1  What are Scripts?
  117.  
  118.      Scripts are files which contain one or more instructions (commands) for
  119.      Intellicomm to carry out.  You can't 'talk' to Intellicomm to tell it
  120.      what to do when you have custom work to do (at least, not to my
  121.      knowledge... <grin>), so the next best thing is to write it down and let
  122.      Intellicomm read it.  As a movie script tells the cast what to say and
  123.      do: Intellicomm scripts tell Intellicomm what to say and do.  You're the
  124.      script writer and Intellicomm is your cast.
  125.  
  126.      Don't confuse scripts with Icom's automated jobs and BIFs.  The jobs you
  127.      run from the Job Directory and set up in the Job Editor are not scripts;
  128.      they're called Jobs and they are carried out by ICOM.EXE's built-in
  129.      automated routines, using BBS Information File (BIF) data.  Jobs are
  130.      jobs, BIFs are BIFs, and scripts are scripts.  They're three different
  131.      things, and this document discusses scripts only.  For information on
  132.      Icom's internal jobs (automated file uploads and downloads, mail
  133.      transfers and time bank transactions, etc.) please refer to the online
  134.      help, and particularly to "BIF Learn".
  135.  
  136.      1.2  Why Should I Bother With Scripts?
  137.  
  138.      There are limitless benefits awaiting those who learn some (or all) of
  139.      Intellicomm's script language, and learn the simple process of creating
  140.      scripts.  Most importantly, you will gain an incredibly flexible and
  141.      powerful tool to add to your automation arsenal.  Virtually ANYTHING you
  142.      can dream up can be automated with a script, while BIFs and automated
  143.      jobs  (aside from the job "Custom Commands" which allow limited custom
  144.      work) were designed for specific tasks.
  145.  
  146.      With scripts you can automate *any* BBS task by watching for specific
  147.      text from the BBS and handling it as you see fit (send responses to the
  148.      BBS, transfer files, display information on the screen, and do any number
  149.      of other things).  If desired, you can easily define your own custom
  150.      interfaces using menus and other interactive functions for interactive
  151.      user input, you can display multiple boxes/windows and other text on the
  152.      screen (including the ability to display incoming text from the *BBS* in
  153.      a window) using a bevy of powerful video-oriented script commands, you
  154.      can run other DOS programs (or .BAT files, or other Icom scripts), pause
  155.      script execution until a specific time and/or day, create, display, and
  156.      otherwise maintain File Tagger catalogs in every way imagineable, read
  157.      from and write to text files on-disk (save information permanently),
  158.      display text files in the File Viewer or load them into the Editor for
  159.      the user to view/modify, test for certain system conditions (date, time,
  160.      day-of-week, etc.), get and set BIF and Icom main setup information,
  161.      create 'keyboard macros', and on and on.
  162.  
  163.      Those who gain control over both Icom's built-in jobs AND its script
  164.      language (and script learn mode, for registered users) truly have the
  165.      most powerful and flexible set of tools available for automated BBS
  166.      communications, probably anywhere in the universe.  If automation, and
  167.  
  168.  
  169.  
  170.  
  171.      Intellicomm v2.01              SCRTUTOR.DOC                              2
  172.      
  173.      
  174.  
  175.      taking the drudgery out of your online sessions is your passion, you
  176.      can't beat that prospect!
  177.  
  178.      1.3  Is This Going to Take HOURS?
  179.  
  180.      Don't be discouraged by the size of the script manuals.  The script
  181.      language and manuals are like a big bowl of peanuts: take what you want. 
  182.      You don't have to eat the whole bowl to enjoy yourself and get something
  183.      useful done, and you'll be able to write very useful scripts after
  184.      reading just the next few pages below.  If you just want the basics, and
  185.      the basics are VERY powerful and useful indeed, you should be finished in
  186.      half-an-hour or less.  If you end up drooling at the possibilities and
  187.      want the whole bowl of peanuts, it'll take some practice (and some more
  188.      reading) to get the whole language down.  But it's your choice, and
  189.      making progress and getting things DONE is a quick process as you'll soon
  190.      see.
  191.  
  192.      You don't even have to print this document if you don't have the time or
  193.      paper: Just read it in the help system ("SCRTUTOR.DOC" link; make sure
  194.      SCRTUTOR.DOC is in the same directory as ICOM.EXE) or text viewer (via
  195.      the Icom File Manager / "View" option) until you're satisfied with what
  196.      you've learned.  The script documents should be used as follows:
  197.  
  198.       1. Read the introductory material in this document until you're happy
  199.          with what you've learned.  This document gives you the basics and,
  200.          more importantly, shows you how to put script commands together to
  201.          get something practical done.
  202.  
  203.       2. Once you've got the basics down, use the "SCRIPT COMMANDS AT A
  204.          GLANCE" section at the beginning of SCRIPT.DOC to find the command(s)
  205.          you're interested in, and to refresh your memory as to what various
  206.          commands do.
  207.  
  208.       3. When you find the command you want, using step 2 above, look it up in
  209.          the DETAILED COMMAND SUMMARY (sorted alphabetically by script
  210.          command) in SCRIPT.DOC to quickly get all the details along with an
  211.          EXAMPLE showing how to use the command.
  212.  
  213.       TIP:  If you view SCRIPT.DOC from Icom's internal File Viewer or help
  214.       system, to locate a command summary press [Alt-F] (Find) then type the
  215.       command you're interested in, follow that with an underscore (e.g.
  216.       PRINT_) then carry out the search DOWNWARDS to find the Detailed Summary
  217.       in a flash.  All commands in the Detailed Command Summary of SCRIPT.DOC
  218.       are followed by a line of underscores to allow you to find commands
  219.       quickly.  The Table of Contents, and the index at the back of the
  220.       manuals can also be used to locate information quickly.  Many people
  221.       skip the Table of Contents, but you can learn a lot by looking at it
  222.       carefully.  You'll see how the manuals are laid out, and more
  223.       importantly can quickly see every major topic that is covered -- which
  224.       can be useful to know when you have a question later.
  225.  
  226.      1.4  Script Learn Mode
  227.  
  228.      The easiest way to become acquainted with scripts is to use Icom's script
  229.  
  230.  
  231.  
  232.  
  233.      Intellicomm v2.01              SCRTUTOR.DOC                              3
  234.      
  235.      
  236.  
  237.      learn mode (a bonus feature in the registered version).  With script
  238.      learn mode you simply turn it on, then just 'do' whatever it is you want
  239.      automated.  Icom watches what you do and writes a script for you!  Not
  240.      only do you save time getting your scripts written, but it's also quite
  241.      educational: by looking at the script Icom creates, you can learn how the
  242.      script language works.
  243.  
  244.      Script Learn is accessed through the "Learn Modes" option of the Main
  245.      Menu or Job Directory or Terminal "Tools" menu, and in various other
  246.      places.  Pressing [Alt-Q] from just about anywhere in Intellicomm calls
  247.      up the Learn Modes menu.
  248.  
  249.      Use of Script Learn is quite straightforward, and is covered in the
  250.      online help if you have questions.
  251.  
  252.      1.5  How Do I Create a Script?
  253.  
  254.      Writing a script (or modifying/adding to one started with Script Learn)
  255.      is much the same as typing a letter in your word processor.  Instead of
  256.      using a word processor though, which places printer commands and
  257.      formatting codes all over the document, you instead use a "Text Editor"
  258.      to create scripts.
  259.  
  260.      Text Editors work similarly to word processors as far as typing,
  261.      deleting, cutting/pasting text, etc.  But they don't add printer codes to
  262.      the files you save to disk -- and they usually don't force margins on
  263.      you, which is essential for writing scripts.  Script command lines will
  264.      sometimes be longer than your screen width, and thus the margins in word
  265.      processors which 'wrap' long lines are not acceptable.  The files Text
  266.      Editors produce are called "text files", or "ASCII files" and these are
  267.      the types of files Icom requires for scripts -- without any printer
  268.      formatting codes or margins.
  269.  
  270.      Intellicomm comes with a built-in Text Editor, though you can use your
  271.      favorite external Text Editor if you like (details in a second).  For
  272.      script writing, the editor (whether internal or external) is best
  273.      accessed through the Icom "Script Manager".  By accessing the Script
  274.      Manager first you can be sure that your scripts will be saved in the
  275.      proper directory; since Icom changes DOS to the Script Directory
  276.      (\ICOM\SCR by default) when you enter the Script Manager.  From the
  277.      editor you just save your scripts in the current directory (without
  278.      specifying a drive letter or \DIRECTORY\ name), and they always end up in
  279.      the right place, where Icom expects them to be.
  280.  
  281.      The Script Manager can be accessed from the Icom Main Menu (and at
  282.      various other menus), or by simply pressing [Alt-U] from just about
  283.      anywhere in Intellicomm.  [Sorry about the 'U'; it doesn't help much in
  284.      remembering the key, but unfortunately [Alt-S] (S for Script) is a fairly
  285.      standard 'Screen Capture' command and is used by the Terminal.]
  286.  
  287.      Once in the Script Manager, select "Create" from the bottom menu to
  288.      create a new script, or hilight the script of interest and select "Edit"
  289.      to view/modify an existing script, or hilight a script and select "Run"
  290.      to execute it (the other options in the Script Manager are fairly self-
  291.  
  292.  
  293.  
  294.  
  295.      Intellicomm v2.01              SCRTUTOR.DOC                              4
  296.      
  297.      
  298.  
  299.      explanatory... please see the online help if you need more information).
  300.  
  301.      There are several scripts included with Intellicomm for demonstration and
  302.      other purposes.  You can enter the Script Manager, hilight and "Run"
  303.      SCRDEMO.SCR from the Script Manager now if you want to see a script in
  304.      action before you continue reading.  SCRDEMO.SCR can also be viewed after
  305.      you run it, for many useful examples.  Note that Intellicomm itself
  306.      doesn't use SCRDEMO.SCR for anything, so you can delete the file when
  307.      you're done with it, if you're short on disk space.
  308.  
  309.      1.6  Icom's Internal Editor vs. an External Editor
  310.  
  311.      If you use Icom's internal Text Editor, you gain the advantage of online
  312.      script writing help (online access to the documentation).  So, when you
  313.      forget one of the script commands we'll be discussing below you can
  314.      simply press the [F1] help key, and call up the index of script help. 
  315.      You can view this document (if installed in the \ICOM directory) or
  316.      SCRIPT.DOC to obtain any information you require, without leaving the
  317.      editor by accessing the SCRTUTOR.DOC or SCRIPT.DOC help links (available
  318.      from the "Script Language" Index, and various other places).
  319.  
  320.      A further advantage of using the internal editor is that if by chance you
  321.      make a typing mistake in your script, then Run the script before noticing
  322.      the error; Icom will be able to load the script into the internal editor,
  323.      position the cursor right on the line of the script where the error
  324.      occurred, displaying the error message to you so you can fix it.  With an
  325.      external editor Icom will still call your editor if an error is found,
  326.      and if your editor accepts a filename on the command line the script will
  327.      be loaded for you, but you won't be moved to the proper line number.  You
  328.      can get the error message (which includes the number of the line on which
  329.      the error occurred) from the file \ICOM\SCRIPT.ERR while in your external
  330.      editor, but unless you're proficient with your external editor and are
  331.      used to doing this sort of thing (with other script languages or program
  332.      compilers), you're probably better off using Icom's internal editor for
  333.      the time being.
  334.  
  335.      To use an external editor you must define the editor command in the Icom
  336.      main setup (accessed via the main menu "Intellicomm Setup" option), on
  337.      the "Filenames and Paths" screen.  Hilight the "Extnl Editor" item, then
  338.      press [Enter] and enter the command you'd normally use to start your
  339.      editor from the *DOS command prompt* there, and save your setup.  Icom
  340.      will then call your external editor when you select "Create" or "Edit"
  341.      from within the Script Manager or when a script error occurs.
  342.  
  343.      If you defined an external editor previously and wish to reverse your
  344.      decision for now and use the internal editor, do the same as outlined
  345.      above but CLEAR the "Extnl Editor" item in the main setup (hold down the
  346.      [Del] key until the item is clear, or press [Ctrl-End] once to clear the
  347.      item while editing it), then re-save your setup.  Icom will then use its
  348.      internal text editor.
  349.  
  350.      1.7  Stopping Scripts
  351.  
  352.      Before we create and run a script, it'll be useful for you to first know
  353.  
  354.  
  355.  
  356.  
  357.      Intellicomm v2.01              SCRTUTOR.DOC                              5
  358.      
  359.      
  360.  
  361.      how to STOP one, if something goes wrong.  To stop a script, just press
  362.      [Alt-Q] (Q for Quit), relax (the script is paused while you're in the
  363.      [Alt-Q] menu or any other menu) then select "Abort Script Only" to cancel
  364.      the script without cancelling the entire job (if the script was called
  365.      during an automated job... more on that later), or select "Abort
  366.      Job/Script" to cancel both the script and the job.  To activate script
  367.      debugging, which runs a script one line at a time, showing you each line
  368.      before it is executed select "Script DEBUG" from the [Alt-Q] menu. 
  369.      Script debug can also be helpful in learning script writing, since it
  370.      slows script execution down, allowing you to study each command before it
  371.      is executed, and see its result after it is executed.
  372.  
  373.      If you forget the [Alt-Q] command, just press [Alt-Z] to pop up the
  374.      Terminal menu (the terminal is where all scripts are executed from,
  375.      regardless of where they're started from) and select "Job and Script
  376.      Control Menu" from the menu, which has the same effect as pressing [Alt-
  377.      Q] from the Terminal.  [Alt-Z] can be your panic button if you forget the
  378.      [Alt-Q] key.
  379.  
  380.      1.8  Creating and Running Your First Script
  381.  
  382.      Most computer language tutorials begin by showing the student how to
  383.      print the message "Hello, World" to the screen.  It's a quick way to
  384.      actually accomplish something, so we'll start by doing this here as well.
  385.  
  386.      To begin, start Icom if necessary, then access the Script Manager by
  387.      pressing [Alt-U].  If [Alt-U] doesn't work, then you're in an area of
  388.      Icom where the hotkeys are disabled, and you'll have to exit that area
  389.      back to any 'major' Icom area, then try again.  Note that these "follow
  390.      along while reading" bits are very quick, so if you're considering
  391.      printing this document now, don't (unless you don't mind doing so).  For
  392.      99% of the tutorial you will simply read along in the online help or File
  393.      Viewer, (without wasting paper) without 'doing' anything but learning. 
  394.      Just grab a piece of paper and write the few short script lines down
  395.      before exiting this document and entering the Script Manager.  Writing
  396.      the commands down also helps the brain to remember things better.
  397.  
  398.      From the Script Manager select "Create" to enter the editor (whether
  399.      internal or external) to create a new script.
  400.  
  401.      Once in the editor type the two lines below, pressing the [Enter] key
  402.      after each line.  If you make a mistake, use the backspace key (just
  403.      above the [Enter] key) to correct it.  Case is not significant when
  404.      entering script commands; 'PRINT', 'Print', and 'print' all do the same
  405.      thing.  Use whichever you prefer:
  406.  
  407.      print "Hello, World!"
  408.      pause
  409.  
  410.      Once you have these two lines entered, save the file as HELLO.SCR and
  411.      exit the editor (from Icom's internal editor, just press the [Esc] key to
  412.      exit, answer "Yes" when asked if you want to save your work, then enter
  413.      HELLO.SCR when asked for a filename.  You're on your own if you're using
  414.      an external editor.  See your editor's help screens if you don't know how
  415.  
  416.  
  417.  
  418.  
  419.      Intellicomm v2.01              SCRTUTOR.DOC                              6
  420.      
  421.      
  422.  
  423.      to save and exit.)  If you're asked whether to overwrite an existing
  424.      file, someone probably gave you a copy of Intellicomm that had already
  425.      been "used" (they already read this and created their own HELLO.SCR).  If
  426.      that's the case just overwrite the existing file when asked.
  427.  
  428.      Once you return to the Script Manager you should see HELLO.SCR displayed
  429.      in the list of script filenames.  To execute the script, move the top
  430.      hilight bar to HELLO.SCR with the [Up] / [Down] cursor keys (or move the
  431.      mouse cursor to HELLO.SCR and click), then select "Run" from the bottom
  432.      menu by pressing the [R] key, or by moving the mouse cursor to "Run" and
  433.      clicking.
  434.  
  435.      Intellicomm should then switch to the Terminal screen, print the message
  436.      Hello, World! to the screen, and pause for a keystroke.  When you press a
  437.      key the script will end and you will be returned to the Script Manager.
  438.  
  439.      Did it work?  If so, congratulations!  If not, please start over, and
  440.      check your typing carefully.  You may have missed a " quote or left a
  441.      space out accidentally.
  442.  
  443.      1.9  A More Exciting Example 
  444.  
  445.      It's nice to be able to print the message "Hello, World" to the screen,
  446.      but it certainly isn't very impressive or exciting.  Let's try something
  447.      a little more interesting this time.
  448.  
  449.      You know what 'menus' are if you've been using Icom for any length of
  450.      time, and now it's time to demonstrate how easy it is to create a menu
  451.      using an Icom script.  You may even impress your friends or co-workers
  452.      with this next script!  
  453.  
  454.      Select "Create" again from the Script Manager to enter the editor and
  455.      create a new script, then type in these three lines exactly, double-
  456.      checking all the quotes, spaces and tildes (~):
  457.  
  458.      MENUDEFINE "Option ~1" "Option ~2" "-" "Option ~3" "Option ~4"
  459.      MENUBOXV "My Own Menu" "Your selection, Sir?"
  460.      PAUSE "You selected Option " $MENUSELECTION
  461.  
  462.      When done, save the script to disk but this time as MENU.SCR (from the
  463.      internal editor, press [Esc], answer "Yes" to save it, then enter
  464.      MENU.SCR when asked for a filename; again overwrite if a MENU.SCR already
  465.      exists).  When you return to the Script Manager, hilight MENU.SCR and
  466.      select "Run" to see what you've created.
  467.  
  468.      If you entered the lines above exactly, you'll have created a centered
  469.      box menu, with title, four menu options with a divider line separating
  470.      items 2 and 3, hotkeys, and mouse support!  Of course, the menu doesn't
  471.      actually 'do' anything yet other than print which option you selected (or
  472.      0 if you press the [Esc] key)... you'd have to add a few more lines to
  473.      the script to get the options to do something.
  474.  
  475.      However, just being able to display such a menu on the screen with
  476.      working hilight bars and mouse support (and even a screen blanker, if
  477.  
  478.  
  479.  
  480.  
  481.      Intellicomm v2.01              SCRTUTOR.DOC                              7
  482.      
  483.      
  484.  
  485.      that feature is turned on in the Icom main setup) is no small programming
  486.      task.  Yet you accomplished it in about 30 seconds!  We used "Option ~1"
  487.      and so forth above, but the options can be any text you like; as long all
  488.      the options remain on the same line, each in double quotes, separated
  489.      from one another by a space.  The "~" character tells MENUDEFINE where
  490.      the 'hotkey' is.  Using a single hypen "-" as a menu option specifies a
  491.      divider line.  
  492.  
  493.      $MENUSELECTION is a 'System Variable' which Icom sets after menu-handling
  494.      commands to tell you which (if any) item was selected from the menu. 
  495.      There are about a hundred of these System Variables available (all
  496.      starting with $) and each is documented fully in SCRIPT.DOC.
  497.  
  498.      By testing the $MENUSELECTION variable with an IF or SWITCH command, you
  499.      could have various other commands carried out according to the menu
  500.      option the user selected.  Example (text after a semicolon ; is ignored
  501.      by the script processor and is used to make comments for human
  502.      consumption):
  503.  
  504.        ;The first IF means "IF $MENUSELECTION is equal to 1"  If it is, then
  505.        ; the command following the IF is executed.  If not, the command is
  506.        ; skipped.
  507.  
  508.       IF $MENUSELECTION = 1
  509.         print "Downloading file..."              ;these commands are only
  510.         download "Z" ""                          ; executed IF $MENUSELECTION
  511.         ...etc.                                  ; is equal to 1
  512.       ENDIF
  513.       IF $MENUSELECTION = 2 gosub Item1Selected  ;go to a subroutine
  514.  
  515.      A better way to test the value of $MENUSELECTION though is to use the
  516.      SWITCH command.  SWITCH is designed specifically to test a variable such
  517.      as $MENUSELECTION for multiple conditions, and to carry out one command
  518.      (or set of commands) according to the value of the variable.  Read the
  519.      comments (after ;) for an explanation:
  520.  
  521.       SWITCH $MENUSELECTION       ;specify the variable to test
  522.        case 1                     ;is $MENUSELECTION equal to 1?
  523.         print "Option 1 selected" ; yes, print this
  524.         ...                       ; execute as many commands as you like
  525.        endcase                    ;'end of case 1' (the rest are skipped)
  526.        case 2                     ;is $MENUSELECTION equal to 2?
  527.         print "Option 2 selected" ; yes, print this
  528.         ...                       ; and execute whatever commands you like
  529.        endcase                    ;'end of case 2' (the rest are skipped)
  530.        ...                        ;and so on with as many 'case/endcase' as
  531.                                   ; needed
  532.        default                    ;default is an optional 'case' that is
  533.         ...                       ; carried out if no other cases are true
  534.        endcase                    ;end of 'default' case
  535.       ENDSWITCH                   ;mandatory 'end of switch' statement
  536.  
  537.      If $MENUSELECTION was equal to 1 (i.e. if the user had selected option 1
  538.      from the menu) then ONLY the command(s) between "case 1" and its
  539.  
  540.  
  541.  
  542.  
  543.      Intellicomm v2.01              SCRTUTOR.DOC                              8
  544.      
  545.      
  546.  
  547.      "endcase" would be executed.  Note that "case 1" isn't fixed text.  You
  548.      won't always use "case 1", "case 2", etc.  In some cases you might use
  549.      this:
  550.  
  551.       case ".ZIP"   ;is the SWITCH equal to ".ZIP"?
  552.       endcase
  553.       case 12345    ;is the SWITCH equal to 12345?
  554.       endcase
  555.  
  556.      ...etc.  Only the word "case" is fixed.  Whatever follows the word "case"
  557.      is compared to the variable specified in the SWITCH ($MENUSELECTION in
  558.      this example) and if they're equal then the commands between that
  559.      case/endcase are carried out.  If they aren't equal, the case (to its
  560.      ENDCASE) is skipped, and the next 'case' is checked.
  561.  
  562.      When you're ready for more information on using menus, see the
  563.      MENUDEFINE, MENUBAR, MENUBOXH, MENUBOXV, IF and SWITCH in the DETAILED
  564.      COMMAND SUMMARY section of SCRIPT.DOC.  Also see SCRDEMO.SCR and
  565.      POSTFILE.SCR for practical examples of menu and SWITCH usage.
  566.  
  567.      1.10  Other Ways of Running Scripts
  568.  
  569.      The scripts you just wrote, as with any Icom script, can be executed in
  570.      all sorts of different ways.  You can run them from BIFs, from Jobs, from
  571.      the DOS command line (using a .BAT file or menu system, for example),
  572.      from another script, or from the Script Manager.
  573.  
  574.      1.10.1  Running Script from BIFs
  575.  
  576.      Scripts can be executed from a BIF by simply specifying @SCRIPTNAME as
  577.      the response to a prompt:
  578.  
  579.      | Your Logon Name> @HELLO                Name . . . . . . st Name? «   |
  580.                         ^^^^^^
  581.      Another useful way to run a script from a BIF is via the "Connect
  582.      Command" item on BIF screen 1.  This command (or @SCRIPTNAME) is executed
  583.      as soon as Icom connects to the BBS, before it gets any logon prompts.
  584.  
  585.      1.10.2  Running Scripts from Jobs
  586.  
  587.      Scripts can also be executed by a job "Custom Command" (defined in the
  588.      Icom Job Editor, where you define all your automated jobs) again by
  589.      specifying @SCRIPTNAME as the Custom Command:
  590.  
  591.      | 12  Custom Command/Run script        |   CC: @MENU                    |
  592.                                                     ^^^^^ 
  593.      The above two methods of running scripts allow you to run any script just
  594.      about ANYWHERE during an automated job.  Note that the .SCR extension is
  595.      not specified in the examples above.  You 'can' specify the extension if
  596.      you like, but Icom supplies the .SCR extension if no extension is given,
  597.      so it's just extra typing to add it (though it can add clarity to specify
  598.      a .SCR extension).  BIFs and Custom Commands are the only two places
  599.      where you must specify '@' before the script name, and the reason for
  600.      that is to tell Icom to run a script instead of doing what it usually
  601.  
  602.  
  603.  
  604.  
  605.      Intellicomm v2.01              SCRTUTOR.DOC                              9
  606.      
  607.      
  608.  
  609.      does: send the text you define to the BBS.
  610.  
  611.      1.10.3  Running Scripts from DOS
  612.  
  613.      Another way to run scripts is via the /scr: command line switch. 
  614.      Example:
  615.  
  616.      ICOM.EXE /scr:MENU
  617.  
  618.      This example above would cause Icom to switch to Terminal mode, run your
  619.      MENU.SCR which we just created, display the menu (and handle any options
  620.      in it, if there were real commands hooked up to the menu), then exit back
  621.      to DOS as with the /run: command line switch, which does much the same
  622.      thing, but for automated jobs instead of scripts.
  623.  
  624.      1.10.4  Running Scripts from Scripts
  625.  
  626.      You can also execute a script FROM a script using the SCRIPT command. 
  627.      Example:
  628.  
  629.      SCRIPT "MENU"           ;run MENU.SCR from another script
  630.      print "Hello, World!"
  631.      pause
  632.  
  633.      If you ran the above script, MENU.SCR would be executed (until
  634.      completion... it could handle all sorts of different tasks) and when
  635.      MENU.SCR finished, the message "Hello, World." would be displayed.  (The
  636.      Hello, World is simply used to show you that the original script
  637.      continues execution after MENU.SCR finishes.)  Again, you can add the
  638.      .SCR extension if you like, but it's not necessary.  Calling one script
  639.      from another is not something many people will have to do, but the
  640.      ability is there if needed.
  641.  
  642.      Note that no @ is required in either of the above examples when
  643.      specifying the script name.
  644.  
  645.      You can also run scripts from scripts by calling up the Script Manager
  646.      and allowing the user to hilight/Run one or more scripts, using the
  647.      SCRIPT command but WITHOUT specifying a script filename after the
  648.      command:
  649.  
  650.       pause "We interrupt this script to bring you the Script Manager..."
  651.       SCRIPT         ;the user could Tag/Run one or more scripts
  652.                      ; ...this script would continue below when all
  653.                      ; the other scripts were finished
  654.       print "We now continue with our regularly scheduled program..."
  655.  
  656.      Note above that instead of using PRINT to print a message, and then PAUSE
  657.      to wait for a keystroke, both were combined into a single PAUSE command. 
  658.      PAUSE accepts an optional message to PRINT before pausing.
  659.  
  660.      1.10.5  Running Scripts from the Script Manager
  661.  
  662.      Of course, scripts can also be executed from the Script Manager by
  663.  
  664.  
  665.  
  666.  
  667.      Intellicomm v2.01              SCRTUTOR.DOC                             10
  668.      
  669.      
  670.  
  671.      pressing [Alt-U] in Icom to access the Script Manager as you've just done
  672.      (the Script Manager can also be used when online, by simply pressing
  673.      [Alt-U] in Terminal mode... Again, it's on the [Alt-Z] terminal menu if
  674.      you forget the key).  You can also Tag and Run scripts one after another
  675.      from the Script Manager, similar to what you can do with jobs from the
  676.      Job Directory -- though this is useful only if the scripts you Tag/Run
  677.      are DESIGNED to run one after the other.  Further, Tagged scripts are
  678.      executed in the ORDER IN WHICH THEY ARE DISPLAYED in the Script Manager,
  679.      but you can easily change this order by renaming scripts (using symbols
  680.      or numbers, like 1SCRIPT.SCR, 2SCRIPT.SCR, or !SCRIPT.SCR to sort to the
  681.      top, etc).
  682.  
  683.      1.10.6  Running Scripts via Function Keys
  684.  
  685.      And if the above isn't enough variety you can also "attach" scripts to
  686.      function keys so a script executes when you press a key.  This is best
  687.      accomplished using Script Learn which asks you whether to attach the
  688.      script to a function key or not.  To attach a script to a key manually
  689.      you must look in the Appendix of the SCRIPT.DOC manual (or in the online
  690.      script help) for the "Key Code" of the function key, and must name the
  691.      script using the numeric key code for the function key to attach to. 
  692.      Zeros must also be padded on the left side of the script name to make it
  693.      exactly eight characters long.  For example if you looked up the Key Code
  694.      for the [F2] key you'd see that was 15360.  To attach a script to the
  695.      [F2] key then, you would name your script 00015360.SCR.  From that point
  696.      on, whenever you pressed the [F2] key from Terminal mode, 00015360.SCR
  697.      would be executed.  
  698.  
  699.      The leading zeroes MUST be added or the script will not execute when you
  700.      press the key (this avoids conflicts with other scripts that just happen
  701.      to use a number as the filename).  Further you must use a function key
  702.      (the key alone, or in combination with [Alt], [Ctrl] or [Shift] ... they
  703.      all have unique Key Codes) and cannot use the [F1] key or any other keys. 
  704.      [F1] is reserved for online help and for future expansion.
  705.  
  706.      1.11  It Can't be That Simple, Can It?
  707.  
  708.      Writing and using scripts can be as complicated or easy as you want it to
  709.      be.  There are many EXTREMELY easy-to-use script commands available to
  710.      put loads of power into your hands with very little effort.
  711.  
  712.      To prove this point further, let's assume that you want to dial a BBS,
  713.      make sure you're connected, perform a complete logon responding to every
  714.      question asked by the BBS, keep an eye out for the BBS main menu so
  715.      you'll know when the logon is complete, AND implement some sort of error
  716.      handling so that if something goes wrong and you don't reach the main
  717.      menu after, say, two minutes, you can give it up and hangup.  To make it
  718.      interesting, you also want to hangup if a BBS event is scheduled, and if
  719.      you DO logon successfully, you want to capture BBS bulletin #5 to a file
  720.      called BLT5.TXT, then logoff and hangup.
  721.  
  722.      If someone asked you to write a script to do this, what would you tell
  723.      them?  You'd probably tell them to get bent (or to use Intellicomm's
  724.      built-in automation routines, which would make a lot more sense), but
  725.  
  726.  
  727.  
  728.  
  729.      Intellicomm v2.01              SCRTUTOR.DOC                             11
  730.      
  731.      
  732.  
  733.      you'll be able to do this on most any BBS just a few minutes from now.
  734.  
  735.      It may seem a rather meaty assignment to be jumping to after "Hello,
  736.      World", and with some script languages you'd be in for a rather
  737.      complicated bit of script writing and concept learning to get the job
  738.      done.  With Intellicomm you get most of the work done with three 
  739.      commands: WHEN, SEND and WAITFOR.  Here's the example (explanation
  740.      follows the example):
  741.  
  742.      dial "Joe's BBS" 1          ;place the call
  743.      offline goto ExitScript     ;jump to label ExitScript: if not connected
  744.      when "Enter Language #"     send "1"
  745.      when "graphics (Enter)=no?" send "N"
  746.      when "st name?"             send "John Smith"
  747.      when "Password"             send "Mypassword"
  748.      when "Scan Message Base"    send "N"
  749.      when "More?"                send "N"
  750.      when "(Enter) to"           send ""
  751.      when "upcoming EVENT"       goto HangItUp
  752.      waitfor "Command? " 120 HangItUp
  753.                                  ;the logon is now complete
  754.      when                        ;clear all the whens, no longer needed 
  755.      cappush                     ;save capture filename/state (open/closed)
  756.      capture "BLT5.TXT"          ;open a new capture file
  757.      send "B 5 NS"               ;get bulletin 5, non-stop mode (PCBoard)
  758.      waitfor "Command? " 120 HangItUp
  759.      cappop                      ;restore the old capture file
  760.      send "G"                    ;send [G]oodbye to logoff
  761.  
  762.      HangItUp:                   ; <-- here is where 'HangItUp' is
  763.      hangup                      ;hangup the modem
  764.  
  765.      ExitScript:                 ; <-- here is where 'ExitScript' is
  766.      exit                        ;end the script
  767.  
  768.      Just twenty lines gets the whole job done... and for demonstration
  769.      purposes the above script is actually more involved than it need be. 
  770.      Ignore the technical details for now (you may still be wondering why
  771.      there are double quotes around some items, etc.) and just take it one
  772.      step at a time.
  773.  
  774.      The DIAL command (the first command in the script) is used to dial a BBS. 
  775.      The text following the dial command tells Icom which BBS to dial: in this
  776.      example Icom would search your BBS Directory for a BIF with a description
  777.      of "Joe's BBS", and if found it would Tag the BIF and "Dial" it.  Note
  778.      the '1' following "Joe's BBS".  This tells DIAL that the BIF description
  779.      must match exactly, and the '1' is optional.  If the 1 is omitted, then
  780.      any portion of any BIF description that had the text "Joe's BBS" in it
  781.      ("Joe's BBS 2", etc) would also be tagged.
  782.  
  783.      Thus, you can also Tag/Dial multiple BIFs, depending on the descriptions
  784.      you use to save your BIFs.  If you had ten BIFs that had exclamation
  785.      marks in their descriptions (Joe's BBS!, CRS!, Sound Advice!, etc), then
  786.      you could just specify the exclamation mark, and omit the '1' following
  787.  
  788.  
  789.  
  790.  
  791.      Intellicomm v2.01              SCRTUTOR.DOC                             12
  792.      
  793.      
  794.  
  795.      the description (i.e. do not force an exact match):
  796.  
  797.      dial "!"
  798.  
  799.      DIAL would then Tag/Dial all ten BIFs.  When the BBS is connected to, it
  800.      is untagged automatically.  REDIAL can then be used to dial the tagged
  801.      BBS's you haven't connected to, until all BIFs are untagged.
  802.  
  803.      The easiest way to find the proper text to use after the DIAL command
  804.      ("Joe's BBS" above), if you intend to tag several BBS's by omitting the
  805.      '1' in the DIAL command, is to enter Icom, press [Alt-D] to switch to the
  806.      BBS Directory and select "Find" from the BBS Directory menu.  Then enter
  807.      the text you intend to use after the DIAL command ("Joe's BBS", without
  808.      the quotes), select "Find all/Tag all", and Icom will show you which BIFs
  809.      would be tagged if you used that text after a DIAL command.  That's
  810.      exactly what DIAL does: it changes to the BBS Directory, then does a
  811.      "Find all/Tag all" on the text you followed the DIAL command with, then
  812.      selects "Dial" from the BBS Directory menu.  By using certain keywords
  813.      (or exclamation points, etc.) in your BIF descriptions you can use this
  814.      to your advantage to dial multiple BBS's with a single DIAL command.
  815.  
  816.      On to the next line: 'offline goto ExitScript'.  Scripts execute from top
  817.      to bottom (first line to last) unless told otherwise by specific
  818.      commands: GOTO is one of those commands, and there are several others. 
  819.      The OFFLINE command checks the modem to see whether it's online or
  820.      offline (connected or not connected).  If the modem ISN'T offline (if we
  821.      got connected), then Icom ignores the GOTO command and simply continues
  822.      with the next line of the script.  If the modem IS offline (we didn't get
  823.      connected), then Icom executes the command following the offline command:
  824.      GOTO in this case.  I.e. an 'if' is implied before the OFFLINE command,
  825.      and you can think of it as "if OFFLINE do this".  GOTO causes Icom to
  826.      goto (jump to) what is called a script 'label'.  The label we're telling
  827.      Icom to goto is label ExitScript:, which gets us down to the end of the
  828.      script rather quickly (EXIT ends a script immediately).  The only time
  829.      you follow a label with a colon (:) is when you're actually showing Icom
  830.      WHERE THE LABEL IS.  I.e. where to GOTO.  You don't follow labels with a
  831.      colon anywhere else.
  832.  
  833.      I said GOTO causes Icom to jump TO the label, but that's not quite true:
  834.      it jumps to the next line following the label.  The label itself can't be
  835.      executed, so that line is skipped and the script starts executing the
  836.      line just following the label.  If labels are found in the normal running
  837.      of a script (we didn't GOTO the label; we just happened to run into it)
  838.      the label is ignored, but any commands BELOW the label are still
  839.      executed.  If that's not what you want, then you simply put a GOTO above
  840.      the label to to jump around the commands.  For example, if the script
  841.      above wasn't designed to logoff the BBS (we didn't want to hangup), we'd
  842.      have to jump around the HANGUP command with a 'GOTO ExitScript' just
  843.      above the label 'HangItUp:'.
  844.  
  845.      We could have just used 'GOTO HangItUp' in the OFFLINE command and
  846.      eliminated the 'ExitScript:' label (the only place the 'ExitScript' label
  847.      is used is by the OFFLINE command).  But there'd be no need to hangup the
  848.      modem if we were offline, so we put one label above the hangup, and can
  849.  
  850.  
  851.  
  852.  
  853.      Intellicomm v2.01              SCRTUTOR.DOC                             13
  854.      
  855.      
  856.  
  857.      GOTO there to hangup and THEN exit the script, and one below the HANGUP
  858.      so we can GOTO there and exit the script without hanging up.  Using
  859.      labels and GOTO's, etc., is how you perform decision-making in your
  860.      scripts, causing some commands to execute under some conditions, and
  861.      other commands (or no commands) to execute under other conditions.  We
  862.      also could have just used OFFLINE EXIT (if offline, exit the script...
  863.      which is simpler than jumping to the label below), but two labels and a
  864.      GOTO were used for demonstration purposes.  
  865.  
  866.      The next command we run across after 'offline goto ExitScript' is the
  867.      WHEN command.  WHEN uses this format:
  868.  
  869.      WHEN "you find this text" do this
  870.  
  871.      ('you' referring to Icom, and 'find' meaning if the text comes in the COM
  872.      port, from the BBS.)  WHEN doesn't actually do anything on its own,
  873.      unless you specify it all by itself, with no parameters following it, in
  874.      which case it CLEARS all the WHENs defined previously.  It's not until
  875.      WAITFOR is executed that the WHENs become active: WHEN and WAITFOR works
  876.      as a team.  WHEN simply causes Icom to store the text and position of the
  877.      command following the WHEN in memory, for later use with WAITFOR. 
  878.      WAITFOR activates all the WHENs (all prompts are then watched for
  879.      simultaneously... you can use up to 19 WHENs at a time) while WAITingFOR
  880.      specific text from the BBS.  Waitfor uses this format:
  881.  
  882.      WAITFOR "wait for this text" <how long> <label to GOTO if not found>
  883.  
  884.      If the text "wait for this text" is found, the WAITFOR command ends and
  885.      the script continues with any lines following the waitfor (above we SEND
  886.      a command to get bulletin 5, open a new CAPTURE file, wait for the menu
  887.      again, then reset the previous capture file and logoff).  The 120 in the
  888.      WAITFOR command in the script above tells WAITFOR how long to wait before
  889.      giving up (in seconds; 120 is two minutes) and 'HangItUp' tells waitfor
  890.      where to jump to (GOTO) if the text ISN'T found within the two minutes. 
  891.      'HangItUp:', defined just below, skips the capture and executes the
  892.      HANGUP command to hang up the modem, then it runs into the EXIT which
  893.      ends the script.  WAITFOR can also be used on its own, without WHENs, if
  894.      you don't need any BBS prompts handled while waiting.
  895.  
  896.      If/when any of the text following any of the WHEN commands comes in from
  897.      the BBS while a WAITFOR is active, Icom executes the command specified by
  898.      that WHEN (and ONLY that command; none of the commands in the other WHENs
  899.      are executed until the text they specify is found).  If the command
  900.      specified in the WHEN doesn't turn control over to another part of the
  901.      script (SEND just sends some text; GOTO turns control over to another
  902.      part of the script), then Icom just executes the command and continues
  903.      waiting for the text specified in the WAITFOR.  If/when the text
  904.      specified by another WHEN is found, the same thing happens, and control
  905.      returns to WAITFOR until the timeout is reached.  I.e. the WHENs are just
  906.      a temporary diversion while WAITingFOR the main objective: the main menu. 
  907.      The WAITFOR timer is not reset after executing the WHEN commands.  Two
  908.      minutes in total, no matter how many times we execute WHEN commands, is
  909.      how long WAITFOR will wait.  I say "wait" because no other commands
  910.      (other than the WHENs) in the script can execute until the WAITFOR either
  911.  
  912.  
  913.  
  914.  
  915.      Intellicomm v2.01              SCRTUTOR.DOC                             14
  916.      
  917.      
  918.  
  919.      finds the text or times out.  I.e. WAITFOR pauses script execution, and
  920.      the lines below a WAITFOR cannot execute until either the text is found,
  921.      or WAITFOR times out.
  922.  
  923.      The commands used in WHEN statements are just regular Icom script
  924.      commands, and you can use any script command (or even a set of commands
  925.      if you use SWITCH, or IF/ENDIF, etc) with a WHEN.  The SEND command, used
  926.      in most of the WHENs above, sends responses to the BBS (no different than
  927.      you typing the response at the keyboard).
  928.  
  929.      Send can also be used on its own to simply send a few commands to the
  930.      BBS.  Send automatically adds a carriage return (same as pressing the
  931.      ENTER key) after the text, so you needn't worry about adding one
  932.      yourself:
  933.  
  934.      send "J 2"          ;PCBoard, join conference 2
  935.      send "D"            ;PCBoard [D]ownload command
  936.      send "ICOM201A.ZIP" ;filename to download
  937.      download "Z"        ;download the file using Zmodem
  938.  
  939.      The example above probably doesn't even need an explanation other than
  940.      the "Z" following the DOWNLOAD command.  When downloading (or
  941.      uploading... UPLOAD is the command in that case), to select a protocol,
  942.      you specify the same letter that you'd press to select the protocol from
  943.      Icom's protocol menu.  If you pressed [PgDn] in terminal mode, you'd see
  944.      that "Z" is the hotkey used on the protocol menu to select Zmodem.  So
  945.      "Z" is what you specify after the DOWNLOAD command in your script to use
  946.      the Zmodem protocol.  You can use other protocols (including any external
  947.      protocols you have set up) in the same way; simply by specifying the
  948.      protocol menu hotkey after the DOWNLOAD command.  You could also do this
  949.      with a WHEN:
  950.  
  951.       WHEN "Start your download" DOWNLOAD "Z"
  952.  
  953.      If/when the text "Start your download" came in from the BBS during a
  954.      WAITFOR, Icom would begin a Zmodem download.
  955.  
  956.      Zmodem doesn't require the name of the file to download since the
  957.      protocol itself (Zmodem at the BBS) passes the filename.  The above
  958.      DOWNLOAD command could even perform a 'batch' Zmodem download, since all
  959.      the logic to perform multiple-file downloads is built into the protocol. 
  960.      No filenames need ever be specified when downloading with Ymodem OR
  961.      Zmodem; the filename(s) are specified by the sender.  Xmodem and its
  962.      cousins Xmodem-1K and Xmodem-1k-G do require a filename, since the Xmodem
  963.      protocol wasn't designed to pass filenames.  Further, since Xmodem
  964.      doesn't pass the filename it cannot perform multiple-file (batch)
  965.      downloads.  If using an EXTERNAL protocol it's up to you to know whether
  966.      the protocol requires a filename on downloads (if it does require a
  967.      filename, the name is specified immediately following the protocol
  968.      letter; Icom will pass the filename to the protocol).  *ALL* protocols
  969.      require filenames for uploads:
  970.  
  971.       UPLOAD "Z" "ICOM201A.ZIP" "ICOM201B.ZIP"
  972.       UPLOAD "Y" "*.ZIP" "D:\TEMP\A???.*"
  973.  
  974.  
  975.  
  976.  
  977.      Intellicomm v2.01              SCRTUTOR.DOC                             15
  978.      
  979.      
  980.  
  981.      The first command would upload ICOM201A.ZIP and ICOM201B.ZIP, using
  982.      Zmodem.  The second would upload any files with a ZIP extension (anywhere
  983.      on the Icom 'Upload PATH' defined in the main setup or current BIF), and
  984.      any file in the D:\TEMP directory with an 'A' followed by any 3
  985.      characters, and any extension.  [Regular DOS wildcards... check your DOS
  986.      manual if you aren't familiar with wildcards.]  Again, you can only
  987.      specify multiple filenames with Ymodem (or Ymodem-G) and Zmodem, or an
  988.      external protocol that supports 'batch' uploads.   Xmodem does not
  989.      support batch uploads or downloads.
  990.  
  991.      You can also create a 'list' of filenames using the Text Editor, then
  992.      have the protocol use the list to get the filenames to upload:
  993.  
  994.       UPLOAD "Z" "@FILES.TXT"
  995.  
  996.      Zmodem would read FILES.TXT, and upload all filespecs on the list.  Each
  997.      filespec may contain a drive/path, and may use wildcards.  When using
  998.      text lists, you specify each filespec on a separate line of the file:
  999.  
  1000.      C:\TEMP\SOMEFILE.ZIP
  1001.      A???.*
  1002.      *.ZIP
  1003.  
  1004.      Note that these rules also apply when uploading manually... you can do
  1005.      all of the above (minus the quotes) when specifying filenames at the
  1006.      Upload filename prompt.
  1007.  
  1008.      1.12  Variable Overview
  1009.  
  1010.      Variables are a very useful script feature, and can increase the
  1011.      usefulness and flexibility of your scripts significantly.  They're not
  1012.      something you 'have' to know about to write scripts, but are something
  1013.      you probably will WANT to know about, since they're extremely useful.
  1014.  
  1015.      Variables are nothing more than "places to put things".  Some variables
  1016.      come with 'things' already in them (information which you can use in your
  1017.      scripts), while other variables are created by you (via the VARIABLE
  1018.      command) to allow you to keep track of your own 'things'.
  1019.  
  1020.      If you wish to count something, such as the number of times a certain
  1021.      error happened, a variable is needed.  If you wish to know what time it
  1022.      is, you use another variable.  There are six different types of variables
  1023.      you can make use of in your scripts, and only a quick overview of
  1024.      variables is given in this section.  Detailed information on all six
  1025.      types of variables, plus many examples of usage, can be found in section
  1026.      4 below.
  1027.  
  1028.      System Variables
  1029.      ~~~~~~~~~~~~~~~~
  1030.      All System Variables begin with a dollar sign ($).  They are used to
  1031.      access all sorts of information about your computer system, and the
  1032.      current status of Intellicomm itself.  They also make your scripts much
  1033.      more flexible, since they allow you to avoid specifying constant data.
  1034.      Examples:
  1035.  
  1036.  
  1037.  
  1038.  
  1039.      Intellicomm v2.01              SCRTUTOR.DOC                             16
  1040.      
  1041.      
  1042.  
  1043.       SEND $PASSWORD                           ;send the BIF logon password
  1044.       PRINT $DATE                              ;prints the current date
  1045.       IF $DOW = 1 PRINT "Today is Sunday"      ;$DOW is the Day-Of-Week
  1046.       IF $DOW = 2 PRINT "Today is Monday"      ; ...etc.
  1047.  
  1048.      The first IF means 'if the day-of-week ($DOW) is equal to 1 (Sunday)',
  1049.      then PRINT "Today is Sunday".  If $DOW is NOT 1, the PRINT following the
  1050.      IF is ignored. 
  1051.  
  1052.      There are a hundred or so different System Variables available and all
  1053.      are outlined quickly in the SCRIPT COMMANDS AT A GLANCE section, and (in
  1054.      more detail) in an appendix at the end of the SCRIPT.DOC manual.  Anyone
  1055.      and everyone can and should use System Variables... they're very
  1056.      straightforward and useful.  As with all the other types of variables
  1057.      listed below, you can use a System Variable in ANY script command that
  1058.      takes a parameter, instead of using constant text or a constant number.
  1059.  
  1060.      User-Defined Variables
  1061.      ~~~~~~~~~~~~~~~~~~~~~~
  1062.      These are variables you define yourself using the VARIABLE command.  If
  1063.      you wish to count something, you might define a variable called 'count':
  1064.  
  1065.       VARIABLE count       ;this command defines variable 'count' and
  1066.                            ; assigns 0 to it (0 is the default)
  1067.       VARIABLE ten 10      ;this command defines variable 'ten' and 
  1068.                            ; assigns 10 to it.
  1069.  
  1070.       INC count            ;INCrement count (count = count + 1)
  1071.       ADD count ten 5      ;count = 10 + 5
  1072.  
  1073.      If you wish to store your name, you might use this:
  1074.  
  1075.       VARIABLE LogonName "John Smith"
  1076.  
  1077.      Later in your script, instead of using SEND "John Smith", you could use
  1078.      SEND LogonName.  These variables also allow you to avoid 'hardcoding'
  1079.      information into your scripts, and thus they allow a single script to
  1080.      serve more than one purpose.
  1081.  
  1082.      Instead of DIAL "Joe's BBS", you can get user input from the keyboard,
  1083.      store the input in a variable, then use the exact same script to dial
  1084.      multiple BBS's.  Further, these variables also make your scripts easier
  1085.      to maintain.  If you define all your variables in one section of the
  1086.      script, and later something changes (a BBS prompt, for example), you can
  1087.      simply change the value assigned to the variable without having to change
  1088.      dozens of WHEN commands.  "Variables" are also what enables Intellicomm
  1089.      to automate calls to different BBS types.  It simply loads the BIF
  1090.      information into its variables... and the program then behaves
  1091.      differently, since it's using different data.
  1092.  
  1093.      Many script commands also REQUIRE a variable as the first parameter, in
  1094.      order to store the results of an operation.  For example the ADD command
  1095.      adds two numbers and stores the result in a User-Defined Variable.  The
  1096.      GETS command gets input from the keyboard, and also stores the input in
  1097.  
  1098.  
  1099.  
  1100.  
  1101.      Intellicomm v2.01              SCRTUTOR.DOC                             17
  1102.      
  1103.      
  1104.  
  1105.      any User-Defined Variable:
  1106.  
  1107.       VARIABLE myvariable    ;define a variable called 'myvariable'
  1108.  
  1109.       GETS myvariable 60     ;get (max) 60 characters from the keyboard, store
  1110.                              ; the input in 'myvariable'
  1111.       PRINT myvariable       ;print the result
  1112.  
  1113.      User-Defined Variables exist only from the time of their creation with
  1114.      the VARIABLE command until the current script ends.  They are also
  1115.      'local' to the current script, so if you execute another script FROM a
  1116.      script with the SCRIPT command you needn't worry about changing the
  1117.      contents of the variables in the first script.
  1118.  
  1119.      The Global Variable Array (GlobalStr)
  1120.      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1121.      This is a variation of the User-Defined Variables.  But the 'Global'
  1122.      Variables exist in memory for the duration of the Icom session.  Unlike
  1123.      the User-Defined Variables, these variables are 'globally' available to
  1124.      all scripts, and still hold their values after the script ends (used
  1125.      mainly for inter-script communication and the like).  They also employ a
  1126.      concept known as an 'array'.
  1127.  
  1128.      The GlobalStr array is where script command line parameters are stored,
  1129.      if you pass parameters to a script from a BIF command, or job Custom
  1130.      Command, or from the DOS command line.  Use of the GlobalStr array is
  1131.      more advanced than most other script concepts and will probably only be
  1132.      needed by advanced script writers.
  1133.  
  1134.      BIF Variables
  1135.      ~~~~~~~~~~~~~
  1136.      These variables allow you to access any information from the BIF
  1137.      currently in use (the BBS you're currently connected to, or the BIF you
  1138.      explicitly load with the LOADBIF command).  BIF variables are also
  1139.      somewhat advanced and probably won't be needed immediately.  See the BIF
  1140.      VARIABLES section in SCRIPT.DOC when you're ready for more information.
  1141.  
  1142.      Main Setup Variables
  1143.      ~~~~~~~~~~~~~~~~~~~~
  1144.      These variables allow you access any information from the INI
  1145.      (INItialization file) currently in use; normally ICOM.INI (you can also
  1146.      load Main Setup files with the LOADINI command).  The Main Setup
  1147.      Variables contain all the main data you define in the Intellicomm Setup. 
  1148.      Again,  these variables are somewhat advanced and you can leave them for
  1149.      the time being.  When you're ready for more information, see the MAIN
  1150.      SETUP VARIABLES section in SCRIPT.DOC.
  1151.  
  1152.      Permanent Variables
  1153.      ~~~~~~~~~~~~~~~~~~~
  1154.      Permanent Variables make use of the script "File Input/Output" commands
  1155.      to store information on-disk.  The concepts aren't overly difficult to
  1156.      grasp, but again won't be needed by everyone.  See the INTRODUCTION TO
  1157.      FILE INPUT / OUTPUT, here in SCRTUTOR.DOC, when you're ready for more
  1158.      information.
  1159.  
  1160.  
  1161.  
  1162.  
  1163.      Intellicomm v2.01              SCRTUTOR.DOC                             18
  1164.      
  1165.      
  1166.  
  1167.      1.13  A Word on Formatting
  1168.  
  1169.      You may have noticed above in some of the example scripts that certain
  1170.      items 'lined up' with each other (the SEND commands after the WHENs, for
  1171.      example), and that the comments are in a certain position, etc.  But this
  1172.      is done only to please the eye, and the only rules that are forced on you
  1173.      as far as formatting goes are these:
  1174.  
  1175.      1. Every script command (including any parameters that follow the
  1176.         command) must be on a separate line.  EXCEPTION: If the script command
  1177.         is designed to take another command as one of its parameters (such as
  1178.         the OFFLINE and WHEN commands demonstrated above), then you may (and
  1179.         must) place more than one command on a single line.  Just don't try to
  1180.         do this:
  1181.  
  1182.          dial "Joe's BBS"  offline exit      ;both on the same line
  1183.  
  1184.       If a command accepts another command as a parameter, the Detailed
  1185.       Summary of the command will tell you so.  If a command isn't expected as
  1186.       a parameter, you can't use one.
  1187.  
  1188.      2. At least one space or TAB character must separate the script command
  1189.         from the parameters (if any), and at least one space/TAB must separate
  1190.         each parameter.  Example:  COMMAND "parameter 1" "parameter 2" ... 
  1191.         These are errors: COMMAND"parameter1" or COMMAND "parm1""parm2".
  1192.                                  ^                              ^
  1193.         One or more spaces (or a TAB) are needed where the carets (^) are.
  1194.  
  1195.      3. Only the first 256 characters of each line are used by the script
  1196.         processor.  You may create lines that are longer than 256 characters
  1197.         (comments that go past the 256 character mark, etc.), but only the
  1198.         first 256 characters are significant to the script processor.  This
  1199.         will probably only be relevant when using the MENUDEFINE command,
  1200.         which uses the format:  MENUDEFINE "Menu Item 1" "Menu Item 2" ...
  1201.         etc.  You'll have to make sure to fit all your menu items in the first
  1202.         256 characters for it to work properly.  If you run into problems, use
  1203.         variables instead of literal strings and use short variable names. 
  1204.         Example:
  1205.  
  1206.          VARIABLE i1 "Menu Item ~1"
  1207.          VARIABLE i2 "Menu Item ~2"
  1208.          ...                         ; "..." denotes more of the same
  1209.          MENUDEFINE i1 i2 ...
  1210.  
  1211.      4. Script 'labels' used to define where a GOTO (and GOSUB) should jump to
  1212.         must on a line by themselves, must be followed by a colon, and there
  1213.         must not be any spaces or tabs anywhere in the label right up to the
  1214.         colon.  The only characters you can use in labels are A-Z, a-z, 1-9,
  1215.         and the underscore (_).  Labels are not case-significant (LABEL: is
  1216.         the same as label:).  NOTE: comments are permitted after labels, but
  1217.         you must put at least one space or TAB between the label and the
  1218.         comment.  Example:
  1219.  
  1220.           HangItUp: ;this label HangItUp
  1221.  
  1222.  
  1223.  
  1224.  
  1225.      Intellicomm v2.01              SCRTUTOR.DOC                             19
  1226.      
  1227.      
  1228.  
  1229.      5. Comments must be preceded by a semicolon (;) and may appear on the
  1230.         same line as a script command or label (after the command/label and
  1231.         all parameters), or may be placed on a line by themselves.  Comments
  1232.         must also be separated from the command/parameters by at least one
  1233.         space or TAB.  These comments are invalid:
  1234.  
  1235.           HangItUp:;This comment isn't separated from the label
  1236.           dial "Joe's BBS";This comment isn't seperated from the parameter.
  1237.         
  1238.       These comments are fine:
  1239.  
  1240.           HangItUp: ;This is fine with a space
  1241.           dial "Joe's BBS" ;This is fine with a space
  1242.  
  1243.       All characters following a semicolon (to the end of the line) are
  1244.       ignored by the script processor.  The one exception to this is if the
  1245.       semicolon is inside quotes.
  1246.  
  1247.      1.14  Why the Double Quotes ""?
  1248.  
  1249.      Double quotes, such as the quotes surrounding the text after the WHEN and
  1250.      SEND commands above are used (a) to keep all the text together as a
  1251.      single unit/parameter, (b) to allow you to use text between the quotes
  1252.      that would otherwise 'mean' something to the script processor
  1253.      (semicolons, for example, which cause Icom to ignore the rest of the
  1254.      line, and spaces or tabs which signify the end of the parameter), and (c)
  1255.      to tell the script processor that it's dealing with literal text instead
  1256.      of a variable.  Variable names are never put in double quotes.
  1257.  
  1258.      A quick note: if the text you're putting between the double quotes has
  1259.      one or more double quotes IN it, then you must 'escape' the double quote
  1260.      with a caret.  Example:
  1261.  
  1262.        "This text has ^"double quotes^" in it"
  1263.  
  1264.      Quotes are never used to surround script commands or labels.  They're
  1265.      only needed in the parameters (if any) following script commands, and
  1266.      only if the parameter is specifying constant TEXT (as opposed to a
  1267.      variable name, or a constant number containing only characters from 0-9).
  1268.  
  1269.      1.15  Specifying Control Characters
  1270.  
  1271.      To specify a control character in a script command parameter (backspace,
  1272.      carriage return, escape, line feed, form feed, Ctrl-A, Ctrl-B, Ctrl-C,
  1273.      etc., are 'control characters') simply precede the control character with
  1274.      a caret (^).  For example, Ctrl-A would be specified as "^A", Ctrl-B is
  1275.      "^B", escape is "^[".  Refer to the ASCII table in the appendix of
  1276.      SCRIPT.DOC (or in the online help) for the complete list of control
  1277.      character codes.  Here's an example of sending two escape characters to
  1278.      the BBS (SENDNC sends without adding a Carriage Return.  The NC means
  1279.      'N'o 'C'arriage Return):
  1280.  
  1281.      SENDNC "^[^["   ;SENDNC doesn't add a CR as SEND does
  1282.  
  1283.  
  1284.  
  1285.  
  1286.      Intellicomm v2.01              SCRTUTOR.DOC                             20
  1287.      
  1288.      
  1289.  
  1290.      If you have to use a caret (^) for some reason, you must use TWO carets
  1291.      or the script processor will either ignore it (if used alone), or will
  1292.      convert the next character to a control character:
  1293.  
  1294.      PRINT "^^"     ;print a single caret
  1295.  
  1296.      To enter the control character ^^ (ASCII code #30), hold down the [Alt]
  1297.      key and type 3 then 0 on the NUMERIC KEYPAD, then release the [Alt] key. 
  1298.  
  1299.      1.16  Tildes
  1300.  
  1301.      You can cause a one second pause between characters with SEND/SENDNC, or
  1302.      SENDNP/SENDNPC by using a tilde (~):
  1303.  
  1304.      SENDNC "^[~^["  ;send ESC, delay for 1 second, send another ESC
  1305.  
  1306.      A delay is almost ALWAYS required by BBS front ends which require you to
  1307.      press ESC twice before logging on.  For some reason, they don't seem to
  1308.      accept two rapid ESCapes.  Again if you want to send a tilde, escape it
  1309.      with a caret:
  1310.  
  1311.      SENDNC "^~"    ;sends a tilde (~)
  1312.  
  1313.      Tildes are only relevant (and need only be escaped with ^) when you use
  1314.      them with SEND/SENDNC or SENDNP/SENDNPC (i.e. when sending data out the
  1315.      COM port).  You needn't and shouldn't escape tildes with a caret in any
  1316.      other script commands.
  1317.  
  1318.      TIP: If you're thinking of writing logon scripts to use in your automated
  1319.      jobs just for this purpose of sending ESC characters to bypass a BBS
  1320.      front end, it is not needed.  Just specify the ESCapes in the BIF
  1321.      "Connect Command" option on the 1st BIF screen:
  1322.  
  1323.      | Dial Prefix  . .                       Connect Command  ^[~^[         
  1324.      |
  1325.  
  1326.      The above Connect Command causes Icom to send an ESC, pause for one
  1327.      second, then send another ESC as soon as it connects to the BBS.  This
  1328.      should get you by most all BBS front ends.
  1329.  
  1330.      1.17  Specifying Numbers
  1331.  
  1332.      When specifying constant numbers in scripts (i.e. in math operations, or
  1333.      when a number is expected as a parameter as with the timeout in WAITFOR)
  1334.      you needn't and shouldn't put quotes around the numbers:
  1335.  
  1336.       GOTOXY 1 1    ;move the screen cursor to the top left corner
  1337.  
  1338.      Why?  Well, numbers never use quotes or semicolons or spaces in them as
  1339.      constant 'strings' (text) might, and they never conflict with variable
  1340.      names since you can't specify a number as the first character of a
  1341.      variable name.  
  1342.  
  1343.      Further, you must not use symbols or commas in the number, unless the
  1344.  
  1345.  
  1346.  
  1347.  
  1348.      Intellicomm v2.01              SCRTUTOR.DOC                             21
  1349.      
  1350.      
  1351.  
  1352.      parameter is to be used as a 'string' and is in quotes (i.e. if using it
  1353.      in a PRINT or WHEN or other command that takes TEXT as a parameter rather
  1354.      than a number).  As soon as the script processor finds a non-numeric
  1355.      character in a parameter -- when it's expecting a NUMBER as a parameter -
  1356.      - it ignores all following characters:
  1357.         
  1358.       ADD result $5.00 $10.00    ;this causes an error, since $ signifies
  1359.                                  ; a System Variable.  Icom would look for
  1360.                                  ; System Variables called 5.00 and 10.00
  1361.                                  ; ...wouldn't find them, and would abort
  1362.                                  ; the script with an error.
  1363.       ADD result "50.5" 30       ;'result' will be 50 + 30 (the quotes are
  1364.                                  ; stripped, the "." is not a number and is
  1365.                                  ; thus ends the 1st number)
  1366.       PRINT "$5.00"              ;text is expected by PRINT, and is in quotes,
  1367.                                  ; so this is fine
  1368.       ADD result 2,000 3,000     ;'result' will be 2 + 3 due to the commas
  1369.       WHEN "2,000" send "3,000"  ;text is expected by WHEN and SEND, and is in
  1370.                                  ; quotes, so this is fine
  1371.  
  1372.      This version of the script language automatically strips quotes from
  1373.      numbers if you use them... so this is 'legal':
  1374.  
  1375.       GOTOXY "1" "1"
  1376.  
  1377.      But the above is not good programming practice and isn't a good habit to
  1378.      get into.  Most programming languages consider it an error to put
  1379.      constant numbers in quotes, since numbers are stored differently by
  1380.      computers than text/strings are.  You should get into the habit of
  1381.      leaving the quotes off when specifying constant numbers, even though it
  1382.      really makes no difference to this version of the script language.
  1383.  
  1384.      1.18  Numeric Limits
  1385.  
  1386.      Constant numbers (or numbers stored in variables that you plan to use in
  1387.      place of a constant number) are limited to the range:
  1388.  
  1389.         -2147483648 to 2147483647
  1390.  
  1391.      That's about two billion negative and positive.  The limits may look like
  1392.      they were picked from a hat, but believe it or not those are 'round'
  1393.      numbers to the computer.  Computers don't count in decimal (base 10) like
  1394.      we do, so you'll rarely find a number rounded to the nearest 10, 100,
  1395.      etc.  The above are the limits of a four "byte" (32 bit) digit.  If you
  1396.      go past the limit in either direction (i.e. add, subtract, multiply or
  1397.      divide numbers that end up with a result higher or lower than the limits
  1398.      above), the result will not be valid.
  1399.  
  1400.      1.19  Compound Statements
  1401.  
  1402.      Compound Statements, while the term might sound scary, are simply groups
  1403.      of script commands on more than one script line, that 'act' similar to a
  1404.      single script line.  Three commands allow compound statements, and each
  1405.      of the three has a 'closing' command to signify the end of the compound
  1406.  
  1407.  
  1408.  
  1409.  
  1410.      Intellicomm v2.01              SCRTUTOR.DOC                             22
  1411.      
  1412.      
  1413.  
  1414.      statement:
  1415.  
  1416.       Command           Closing Command
  1417.       ---------------------------------
  1418.        IF                  ENDIF
  1419.        SWITCH              ENDSWITCH
  1420.        WHILE               ENDWHILE
  1421.  
  1422.      Here's an example:
  1423.  
  1424.       variable x
  1425.       variable y
  1426.  
  1427.       IF x = y
  1428.        print "x is equal to y"
  1429.        pause "Please press a key..."
  1430.        return
  1431.       ENDIF
  1432.  
  1433.      You'll notice above that three commands were placed between the IF and
  1434.      ENDIF.  If the comparison turned out to be TRUE (if x was equal to y),
  1435.      then all three commands would be executed.  If the comparison turned out
  1436.      to be FALSE (if x was NOT equal to y) then everything between the IF and
  1437.      ENDIF is skipped.
  1438.  
  1439.      You can also "nest" compound statements, or in other words you can place
  1440.      compound statements INSIDE of other compound statements like this:
  1441.  
  1442.       IF x > y     ;is x greater than y?
  1443.        IF x = 0
  1444.         print "x is equal to zero"
  1445.         return
  1446.        ENDIF       ;end of the second IF
  1447.        WHILE x > y
  1448.         print x
  1449.         dec x      ;DECrement (x = x - 1)
  1450.        ENDWHILE    ;end of the WHILE
  1451.       ENDIF        ;end of the first IF
  1452.  
  1453.      The first IF above works in exactly the same way as the first example. 
  1454.      If x is greater than (>) y then the commands between the first IF/ENDIF
  1455.      pair are evaluated.  If x is NOT greater than y, then everything is
  1456.      skipped right down to the last ENDIF.  There is no limit as to how many
  1457.      compound statements you can nest, and the second IF above could have
  1458.      another IF, SWITCH or while before its ENDIF, and so forth.
  1459.  
  1460.      It's important to understand that these compound statements ACT as a
  1461.      single script command, for cases such as these:
  1462.  
  1463.       ONLINE SWITCH next_job
  1464.               case 1
  1465.                gosub do_job_1
  1466.               endcase
  1467.               case 2
  1468.  
  1469.  
  1470.  
  1471.  
  1472.      Intellicomm v2.01              SCRTUTOR.DOC                             23
  1473.      
  1474.      
  1475.  
  1476.                gosub do_job_2
  1477.               endcase
  1478.              ENDSWITCH
  1479.  
  1480.      Above if the modem WAS online, then the SWITCH compound statement (to the
  1481.      ENDSWITCH, executing one or none of the 'cases') would be evaluated.  If
  1482.      the modem WASN'T online, then the entire SWITCH (along with any nested
  1483.      compound statements WITHIN the SWITCH/ENDSWITCH) is ignored.  This is
  1484.      also legal:
  1485.  
  1486.       ONLINE IF x = y SWITCH
  1487.                        ...      ;CASE/ENDCASEs here, along with even more
  1488.                        ...      ; compound statements if need be
  1489.                       ENDSWITCH
  1490.  
  1491.  
  1492.      Note that if a command is specified after the IF comparison (after 'x =
  1493.      y' above), then it is assumed that you are using the stand-alone version
  1494.      of IF, instead of using an IF/ENDIF compound statement.  Example:
  1495.  
  1496.        IF x = y PRINT "x = y"
  1497.  
  1498.        IF x = y
  1499.         PRINT "x = y"
  1500.        ENDIF
  1501.  
  1502.      Both of the above do the same thing...  One uses the stand-alone IF
  1503.      variation (where only one command, or a compound statement is accepted
  1504.      after the comparison) and one uses the IF/ENDIF variation.  In the
  1505.      previous example, the SWITCH is legal after the IF comparison since
  1506.      compound statements (and nested compound statements) behave like single
  1507.      script commands.  Thus, if the modem was NOT online then everything right
  1508.      to the ENDSWITCH would be skipped.  If the modem WAS online then the IF
  1509.      would be evaluated... and again if x was NOT equal to y, then everything
  1510.      to the ENDSWITCH would be skipped.  If x WAS equal to y, then the SWITCH
  1511.      would be evaluated.  Nested commands (compound or otherwise) progess one
  1512.      step at a time, and whenever something proves to be false, the very next
  1513.      command, be it a single command, a compound statement, or multiple nested
  1514.      compound statements, is skipped.
  1515.  
  1516.      Only after you gain a bit of experience will you want to get into
  1517.      compound statement nesting, but you're bound to run into it sooner or
  1518.      later (and it certainly can be quite useful at times) so it's handy to
  1519.      know how they work.
  1520.  
  1521.      1.20  Where To Go From Here
  1522.  
  1523.      Congratulations!  This ends the introduction.  You could quit with this
  1524.      knowledge right now and write some very useful scripts indeed.  You know
  1525.      what scripts are, how to write them, how to run them in every way
  1526.      imaginable, how to display information on the screen, including working
  1527.      menus, how to dial a BBS, how to watch for BBS text/send responses, how
  1528.      to perform error handling if key BBS text you're looking for isn't found,
  1529.      how to upload and download files, how to hangup the modem, how to perform
  1530.  
  1531.  
  1532.  
  1533.  
  1534.      Intellicomm v2.01              SCRTUTOR.DOC                             24
  1535.      
  1536.      
  1537.  
  1538.      basic decision-making (GOTO), how to define and use variables, and in
  1539.      general how to use compound and nested compound statements!  And you
  1540.      should be able to accomplish just about anything with these skills.
  1541.  
  1542.      There are many more script commands in Icom's script language not
  1543.      demonstrated above that are just as easy to learn and use, just as
  1544.      useful, and will require little explanation to use.  If you understood
  1545.      the examples above you'll have no trouble understanding most of the other
  1546.      script commands... It's only a matter of time and hands-on experience
  1547.      until you master scripts completely.  And when you master scripts, a
  1548.      whole new world of possibilities will open up to you!
  1549.  
  1550.      Your next step should be to execute the SCRDEMO.SCR (script demo) script
  1551.      if you haven't already, and to then "Edit" SCRDEMO.SCR to see how various
  1552.      tasks were accomplished.  When you see a command you're not familiar
  1553.      with, either use the online help "SCRIPT.DOC" link, or the File Viewer
  1554.      (accessable in the Editor via the File|DOS/Open... menu option) to look
  1555.      up the detailed summary of any commands you don't understand, or simply
  1556.      want to read up on.
  1557.  
  1558.      All script commands and System Variables are outlined in the SCRIPT
  1559.      COMMANDS AT A GLANCE section of SCRIPT.DOC, and each command is explained
  1560.      in detail in the DETAILED COMMAND SUMMARY section.  EXAMPLES of usage for
  1561.      each command can also be found in the Detailed Summaries.  
  1562.  
  1563.      1.21  The Secret to Success
  1564.  
  1565.      The only real problem you have when writing scripts is in remembering the
  1566.      commands, and remembering what 'parameters' follow the commands (like the
  1567.      "Z" after the DOWNLOAD command).  The trick is to ONLY concentrate on the
  1568.      commands you NEED, and to learn (then USE) only one or two commands at a
  1569.      time.  Practice makes perfect; take one or two script commands that you
  1570.      need, practice with them and get a script WORKING with them, and only
  1571.      then move on to other commands you may need.  You WILL succeed if you
  1572.      take this approach.
  1573.  
  1574.      Most people will use only 5% or 10% of the script commands, and will
  1575.      never bother the other 90% (though 'which' 10% of the script language
  1576.      each user concentrates on varies from person to person, depending on
  1577.      their needs) so don't bother with a command until you need it.  Perhaps
  1578.      start with WHEN and SEND, to define your own logon script (note that you
  1579.      MUST define a password in your BIF or Icom will not attempt an auto-
  1580.      logon).  Practice calling the logon script from a BIF by placing
  1581.      @SCRIPTNAME in the BIF "Connect Command" item on BIF screen 1:
  1582.  
  1583.      | Dial Prefix  . . 1                Connect Command  @SCRIPTNAME        |
  1584.  
  1585.      SCRIPTNAME.SCR would be executed as soon as Icom makes a connection at
  1586.      that BBS.  Try getting the script to answer just one or two logon
  1587.      questions such as your name and password ... get that working, THEN move
  1588.      on to other things.  Or you could practice running a script from one of
  1589.      the BIF Logon responses:
  1590.  
  1591.      | Your Logon Name> @SCRIPTNAME      Name . . . . . . st Name? «         |
  1592.  
  1593.  
  1594.  
  1595.  
  1596.      Intellicomm v2.01              SCRTUTOR.DOC                             25
  1597.      
  1598.      
  1599.  
  1600.      SCRIPTNAME.SCR in the example above would start with:
  1601.  
  1602.      SEND "John Smith"
  1603.  
  1604.      since Icom would already have found the "st Name?" prompt ... The script
  1605.      might then continue to define some WHENs to handle other logon prompts:
  1606.  
  1607.      WHEN "dots will echo)?" SEND $PASSWORD  ;sends the BIF password
  1608.      WHEN "last read" SEND "N"
  1609.      WAITFOR "Command?" 120
  1610.  
  1611.      Icom will pick things up wherever your script leaves off (assuming the
  1612.      proper BIF Logon information is defined).  You can run a script to answer
  1613.      a SINGLE logon prompt, or you can handle the entire logon (even carrying
  1614.      out a side-job such as capturing the BBS news file, etc.) and leave Icom
  1615.      at the BBS Main Menu.  The same applies to mail runs, bank transactions,
  1616.      file transfers, etc.  You can execute a script in ANY BIF response slot. 
  1617.      As long as the script carries out (at minimum) what the internal BIF
  1618.      command its replacing did (opening a DOOR, etc), you should be fine.
  1619.  
  1620.      Only when you become familiar with these basic concepts and gain
  1621.      experience should you move on to more complex scripts (if you want to
  1622.      learn more... stop whenever you're satisfied with what you've learned). 
  1623.      Browse the SCRIPT COMMANDS AT A GLANCE section often in the beginning,
  1624.      just so that you'll at know what commands ARE AVAILABLE for specific
  1625.      tasks.  Don't try to memorize any commands... just give it a quick browse
  1626.      so you'll know, in general, what is available.  Only when you NEED that
  1627.      task done in a script will you have to bother learning how the command
  1628.      actually works.  Imagine the script language as a big plate of assorted
  1629.      appetizers, meant to serve everyone: look the plate over (the SCRIPT
  1630.      COMMANDS AT A GLANCE section), and take what you want.
  1631.  
  1632.      With just a little time and experience, you'll be able to write very
  1633.      powerful scripts that will AMAZE you and give you great satisfaction. 
  1634.      Enjoy yourself, and be proud of your accomplishments!  Writing scripts
  1635.      that WORK, no matter how insignificant the task, can be a very satisfying
  1636.      way to spend an evening or two.
  1637.  
  1638.  
  1639.  
  1640.  
  1641.      Intellicomm v2.01              SCRTUTOR.DOC                             26
  1642.      
  1643.      
  1644.  
  1645.                         2.  WHAT HAPPENS WHEN A SCRIPT ENDS?
  1646.  
  1647.  
  1648.      The short answer to what happens when a script ends is, "hopefully the
  1649.      right thing, for whatever circumstances the script left the system in". 
  1650.      The longer answers follow:
  1651.  
  1652.      Scripts end when one of four things happen: (1) the end of the script is
  1653.      reached (there are no more commands to execute; this is true even if a
  1654.      subroutine was executed and you forgot to add a RETURN), (2) Icom runs
  1655.      across an EXIT or RETURN or SYSTEM command in a script, which ends the
  1656.      script at that point, (3) the connection is lost and Icom was running an
  1657.      automated job prior to calling the script, (4) the user aborts the script
  1658.      by pressing [Alt-Q] then selecting "Abort Job/Script" or "Abort Script
  1659.      Only" from the control menu.  If the user selects "Abort Job/Script" then
  1660.      both the script and the automated job are cancelled.
  1661.  
  1662.      When any of the four events above occur, what Icom will do next depends
  1663.      on whether your modem is connected or not connected (online or offline),
  1664.      where you called the script from, and whether an 'errorcode' was returned
  1665.      by the script in the EXIT or RETURN command.
  1666.  
  1667.      If you run a script from an automated job via a Custom Command, the first
  1668.      thing Icom will do when the script ends is attempt to locate its position
  1669.      on the BBS by sending the BIF "General Menu Exit" command, then watching
  1670.      for a BBS menu (the script may have changed locations, so Icom can't
  1671.      assume it ended up where it was when the script started).  If Icom
  1672.      successfully locates its position, the next job task continues (Get Mail,
  1673.      etc., or perhaps even another Custom Command that runs another script).
  1674.        
  1675.      If you call a script from a BIF, by using @SCRIPTNAME in one of the BIF
  1676.      command responses, Icom expects that YOU have made sure that your script
  1677.      did the appropriate thing, and left Icom in the location it needed to be
  1678.      in for whatever it'll be doing next (the same as any command you define
  1679.      in a BIF; you can define anything you want, but if it doesn't do the
  1680.      right thing, your job will probably fail).
  1681.  
  1682.      If you call a script from the Script Manager, after the script stops
  1683.      running Icom checks to see whether you're online or offline, and if
  1684.      online it leaves you in Terminal mode to continue with your BBS session. 
  1685.      If the modem is offline when the script ends, Icom returns to the Script
  1686.      Manager (unless you originally entered the Script Manager from Terminal
  1687.      mode using [Alt-U] ... in that case, as with most 'sub-tasks' you execute
  1688.      from Terminal mode, you are returned to the terminal when the script
  1689.      ends).  
  1690.  
  1691.      If you run a script from DOS via the /scr: command line switch:
  1692.  
  1693.      ICOM.EXE /scr:MYSCRIPT
  1694.  
  1695.      Icom automatically returns *to DOS* if the modem is OFFLINE when the
  1696.      script ends; but not until processing ALL command line switches.  This
  1697.      command is legal:
  1698.  
  1699.  
  1700.  
  1701.  
  1702.      Intellicomm v2.01              SCRTUTOR.DOC                             27
  1703.      
  1704.      
  1705.  
  1706.      ICOM.EXE /scr:MYSCRIPT /run:"Some automated job"
  1707.  
  1708.      Icom would run the script, then the automated job, and THEN if the modem
  1709.      was offline it would return to DOS (note that Icom always saves /Run:
  1710.      switch until ALL other command line parameters are processed.  If you put
  1711.      the /run: first, and the /scr: second, the script would still be executed
  1712.      first).  If you do something like the above, your script would have to
  1713.      perform the dialing/logon, and would have to either leave Icom connected
  1714.      to the BBS that the job is set up to run on, or would have to HANGUP
  1715.      before exiting so that the job would dial.  If Icom is connected when a
  1716.      job is started it assumes you've already connected to the proper BBS and
  1717.      simply begins the job without dialing.  If you aren't connected to the
  1718.      proper BBS, the job will probably fail.
  1719.  
  1720.      This is also legal:
  1721.  
  1722.      ICOM.EXE /scr:"SCRIPT1 parm1 parm2" /scr:"SCRIPT2 parm1 parm2"
  1723.  
  1724.      (See section 4.10 for more information on passing parameters to scripts.)
  1725.  
  1726.      If the modem is ONLINE when the script ends (rather, when all command
  1727.      line options are processed) then Icom switches to manual terminal mode. 
  1728.      If the modem is OFFLINE, Icom exits back to DOS.  If you're designing a
  1729.      script to be called with the /scr: command line option via a .BAT file or
  1730.      menu system (or Windows/DESQview), make sure that you execute the HANGUP
  1731.      command before exiting your script, if you want Icom to exit back to
  1732.      where it was called from (back to DOS, the .BAT file, or menu system).
  1733.  
  1734.      2.1  EXIT and RETURN Error codes
  1735.  
  1736.      If you use an EXIT or RETURN command in your script, and specify a
  1737.      negative number as the exit code (EXIT -1, EXIT -2, RETURN -1, RETURN -2,
  1738.      etc), then Icom cancels all automated jobs, hangs up, and returns to
  1739.      whatever called it (the Job Directory/Main Menu if an automated job, the
  1740.      Script Manager if called from there, or DOS if called via the /scr:
  1741.      command line option).  Using a negative exit code after EXIT or RETURN is
  1742.      a rather potent option that should only be used when the circumstances
  1743.      warrant it.
  1744.  
  1745.      If a positive number follows the EXIT or RETURN command (EXIT 1, EXIT 2,
  1746.      RETURN 1, RETURN 2, etc.) then Icom removes the current BIF from the job
  1747.      queue, hangs up, and won't carry out any further jobs on that BBS (if
  1748.      multiple jobs were Tagged for the current BBS) during the current
  1749.      automated session.  Use this one when you run out of time at a BBS, or an
  1750.      EVENT is scheduled, etc., and you don't want to call that BBS back.
  1751.  
  1752.      If zero (0) or no error code is specified after the EXIT or RETURN
  1753.      command (EXIT 0, RETURN 0, or just EXIT or RETURN alone), or the script
  1754.      simply reaches the end without any EXIT/RETURN at all, then it's a
  1755.      regular exit and the the usual rules that govern what happens when a
  1756.      script ends (outlined above) apply.  This is what will be used in 99% of
  1757.      the cases to end a script.
  1758.  
  1759.      NOTE: This only applies to the RETURN command when it's used to actually
  1760.  
  1761.  
  1762.  
  1763.  
  1764.      Intellicomm v2.01              SCRTUTOR.DOC                             28
  1765.      
  1766.      
  1767.  
  1768.      exit a script: I.e. if the RETURN is found OUTSIDE of a subroutine (a
  1769.      GOSUB command was not executed previously).  If you're simply RETURNing
  1770.      from a subroutine, error codes are ignored.  EXIT is used to exit all
  1771.      scripts (if you call a script from a script and want to abort BOTH
  1772.      scripts) while RETURN is used to simply exit the current script back to
  1773.      the caller.
  1774.  
  1775.      2.2  Using the HANGUP Command for Error-Recovery
  1776.  
  1777.      If your script is called by an automated job (Custom Command or BIF
  1778.      command) and loses track of its position or just can't get out of a
  1779.      tricky situation, the easiest way to recover is to execute a script
  1780.      HANGUP command.  This will cause the modem to hangup, and when the
  1781.      connection is lost Icom will abort the script, notice the carrier loss
  1782.      (if during an automated job) and will call the BBS back if any job tasks
  1783.      remain unfinished.  Losses of connection are tracked by Icom, and it will
  1784.      only permit *three* losses of connection before removing the BIF from the
  1785.      job queue.  If you use the HANGUP command from a script during an
  1786.      automated job, it simply looks like a regular loss of connection to
  1787.      Intellicomm.
  1788.  
  1789.  
  1790.                       3.  INTRODUCTION TO SUBROUTINES (GOSUB)
  1791.  
  1792.      Subroutines are indespensible in any programming language.  They allow
  1793.      you to carry out complicated tasks with a single script command -- GOSUB,
  1794.      short for "GO" to "SUB"routine.  Subroutines are also useful in cutting
  1795.      down on programming/typing errors, since you can write and debug a
  1796.      routine ONCE, then make use of that same bug-free routine in several
  1797.      places in the script.  Without subroutines you would be forced to write
  1798.      repetitive sequences of script commands multiple times, thus increasing
  1799.      the chance of making a typing error, or introducing a bug.
  1800.  
  1801.      3.1  When to use a Subroutine
  1802.  
  1803.      Subroutines should be used to replace repetitive sequences of script
  1804.      commands.  For example, if you're doing something like printing a 'Press
  1805.      a key' message, then clearing the screen, you might as well use a
  1806.      subroutine to avoid repeating the exact same commands in multiple places
  1807.      in the script:
  1808.  
  1809.      PressAKey:
  1810.       PAUSE "Press a key... "  ;wait for a key press
  1811.       CLS                      ;clear the screen
  1812.       RETURN                   ;return from the subroutine
  1813.  
  1814.      Once the subroutine is in place, whenever and wherever you need to pause
  1815.      for a keypress in your script, you just execute the command:
  1816.  
  1817.       GOSUB PressAKey
  1818.  
  1819.      When the script processor runs across a GOSUB command it first saves its
  1820.      current position in the script (the position of the GOSUB command), then
  1821.      it does the equivalent of a GOTO (jumps to the label specified after the
  1822.  
  1823.  
  1824.  
  1825.  
  1826.      Intellicomm v2.01              SCRTUTOR.DOC                             29
  1827.      
  1828.      
  1829.  
  1830.      GOSUB) and begins executing the script at the next line after the label. 
  1831.      When a RETURN statement is found, it then restores the position it saved
  1832.      previously, and continues running the script at the next line below the
  1833.      GOSUB command.
  1834.  
  1835.      Subroutines can also be used to make a script easier to follow and thus
  1836.      easier to maintain (add to) and debug.  They can also help you to
  1837.      organize your thoughts when you have a complex task to accomplish. 
  1838.      Instead of trying to figure out how you're going to fit a complicated set
  1839.      of commands into the EXISTING structure of your script, you can instead
  1840.      write the complicated code elsewhere (concentrating only on one task at a
  1841.      time) in a subroutine, without making a mess of the existing structure of
  1842.      your script.
  1843.  
  1844.      Finally, you can also do the equivalent of inventing new script commands
  1845.      with subroutines.  Computer (and script) languages give you "building
  1846.      blocks" in the commands they provide.  You won't always find a single
  1847.      command that does exactly what you need, but you can usually get
  1848.      virtually ANY job done by combining two or more commands and placing them
  1849.      in a subroutine.  Once the subroutine is written, it becomes basically as
  1850.      easy to use as a built-in script command is.
  1851.  
  1852.      3.2  Writing a Subroutine
  1853.  
  1854.      Writing a subroutine is no different than writing any other portion of
  1855.      your script, with two exceptions: you must think up a 'name' for a
  1856.      subroutine, and you must use a RETURN command to exit the subroutine
  1857.      (back from where it was called).   Example:
  1858.  
  1859.      MySubroutine:
  1860.       print "I am now in 'MySubroutine'"
  1861.       return
  1862.  
  1863.      The above subroutine is called 'MySubroutine' and it could be executed
  1864.      from anywhere in a script using the command:
  1865.  
  1866.       GOSUB MySubroutine     ;note that the colon is not specified
  1867.  
  1868.      Subroutines can be placed anywhere in your script, though the most common
  1869.      place to put new subroutines is right at the end of the script.  The
  1870.      reason they will normally be placed at the 'end' is so you can easily
  1871.      avoid running into them by placing an EXIT (or RETURN) command just above
  1872.      the beginning of all your subroutines.  Example:
  1873.  
  1874.       GOSUB InitScript    ;Initialize (define and set up any variables)
  1875.       ...                 ;main body of script here
  1876.       EXIT                ;EXIT (or RETURN) after the main body
  1877.  
  1878.       ;Now you can't run into 'InitScript' accidentally
  1879.  
  1880.      InitScript:
  1881.       ...
  1882.       RETURN              ;and you can't run into 'Subroutine2' accidentally
  1883.  
  1884.  
  1885.  
  1886.  
  1887.      Intellicomm v2.01              SCRTUTOR.DOC                             30
  1888.      
  1889.      
  1890.  
  1891.      Subroutine2:         ;and so forth...
  1892.       ...
  1893.       RETURN
  1894.  
  1895.      Subroutine3:
  1896.       ...
  1897.       RETURN
  1898.  
  1899.      Remember that the script processor simply ignores 'Labels:' if if happens
  1900.      to run into them in the normal course of running a script.  Without the
  1901.      EXIT and RETURNs above, all the subroutines would be executed when the
  1902.      main body of the script ran into the subroutine labels below it.
  1903.  
  1904.      3.3  GOSUB In Detail
  1905.  
  1906.      When the script processor runs across a GOSUB command, it first saves its
  1907.      current position (the 'current' position will be the END of the line on
  1908.      which the GOSUB was found), then searches from the top of the script for
  1909.      the 'Label' you specify AFTER the GOSUB command.  If the label is found,
  1910.      execution of the script then begins on the next script line after the
  1911.      label (labels, which are always followed by a colon, are always ignored). 
  1912.      The next time a RETURN is found (whether it was actually in the
  1913.      subroutine or not; you can GOTO out of one subroutine and execute
  1914.      another, then RETURN from there) the position saved when the GOSUB found
  1915.      is then 'popped' off the GOSUB stack, and script execution returns to the
  1916.      next command after the *last* GOSUB (if any).
  1917.  
  1918.      The GOSUB 'stack' (the place where the script processor saves the
  1919.      position of GOSUB commands, before executing the subroutine) can hold 16
  1920.      positions.  Thus, you can execute up to 16 'nested' GOSUB commands (GOSUB
  1921.      from *within* a subroutine) before executing a single RETURN.  If you
  1922.      attempt to execute 17 GOSUBs before using a RETURN, you earn a "GOSUB
  1923.      Stack Overflow" error, and your script aborts.
  1924.  
  1925.      As RETURN commands are encountered, the script processor returns to the
  1926.      position of the *last* GOSUB command.  Example (see the comments [;] for
  1927.      an explantion):
  1928.  
  1929.      GOSUB Subroutine1
  1930.      exit
  1931.  
  1932.      Subroutine1:
  1933.       print "Executing subroutine 1."
  1934.       GOSUB Subroutine2
  1935.       RETURN   ;would return to the EXIT below 'GOSUB Subroutine1' above
  1936.  
  1937.      Subroutine2:
  1938.       print "Executing subroutine 2."
  1939.       RETURN   ;would return to the RETURN below 'GOSUB Subroutine2' above
  1940.  
  1941.      And again, it makes no difference whether the RETURN commands are
  1942.      actually 'in' the subroutine.  If 'GOTO Subroutine2' was used above,
  1943.      instead of GOSUB, the RETURN found in Subroutine2 would cause a return to
  1944.      the EXIT command below the call to Subroutine1.  Just picture the
  1945.  
  1946.  
  1947.  
  1948.  
  1949.      Intellicomm v2.01              SCRTUTOR.DOC                             31
  1950.      
  1951.      
  1952.  
  1953.      positions of your GOSUB commands being placed in a hat one after the
  1954.      other (you can't get to the previous position without removing the last
  1955.      one) with the RETURN command simply removing those positions (last in,
  1956.      first out) and you'll have no surprises.
  1957.  
  1958.      Note also that there is no difference between a GOTO label, and a GOSUB
  1959.      label.  You can GOTO a subroutine label if you like -- but be cautioned
  1960.      that if a RETURN is found -- and no GOSUB was executed previously (i.e.
  1961.      there are no saved positions on the subroutine stack), it causes the
  1962.      script to end.
  1963.  
  1964.      3.4  Creating a Subroutine Template
  1965.  
  1966.      If you find yourself writing the same subroutines over and over again in
  1967.      your scripts, you should consider creating one or more subroutine
  1968.      "template" files, which contain your common subroutines.  You can call
  1969.      template files anything you like: TEMPLATE.SCR is a good choice.  Then,
  1970.      whenever you begin writing a new script, simply hilight TEMPLATE.SCR,
  1971.      select "Copy" from the Script Manager, and copy it to another filename
  1972.      (the name of the script you wish to create).  Then begin your script by
  1973.      "Edit"ing the newly copied template.
  1974.  
  1975.      All the subroutines will be in place, and you can begin coding
  1976.      immediately.  This practice will also help you to standardize the names
  1977.      of your subroutines, so that you're always using the same subroutine
  1978.      label for a specific function (PressAKey, instead of Press_a_Key,
  1979.      PressKey, etc., which could get confusing after a time).  It will also
  1980.      give you more reliable scripts, since you'll be using (hopefully) tested
  1981.      subroutines instead of writing from scratch, where you might make a
  1982.      mistake.
  1983.  
  1984.  
  1985.  
  1986.  
  1987.      Intellicomm v2.01              SCRTUTOR.DOC                             32
  1988.      
  1989.      
  1990.  
  1991.                            4.  SCRIPT VARIABLES IN DETAIL
  1992.  
  1993.  
  1994.      4.1  Why Would I Want to Use Variables?
  1995.  
  1996.      Variables are what allow computer programs (and scripts) to "know"
  1997.      something.  They give your scripts a memory so that they can remember
  1998.      things, and thus become smarter.  If an error occurs, you can have the
  1999.      script remember the error or count the occurrences of errors through the
  2000.      use of variables.  If you need the user to enter something (a phone
  2001.      number or the like), you can have your script store what the user enters
  2002.      in a variable, and thus your script can 'remember' what the user entered. 
  2003.      Without variables, scripts have no way of remembering anything at all.
  2004.  
  2005.      Variables are also REQUIRED by several of the script commands.  If you
  2006.      want to do any math (add, subtract, multiply, divide numbers) get
  2007.      keyboard input from the user, read text files on-disk, or do any sort of
  2008.      string 'handling' (joining two pieces of text together, extracting
  2009.      characters from a line of text, reading text from the video screen, etc.)
  2010.      then you must use variables to store the results.
  2011.  
  2012.      There are six types of variables in the Icom script language: 'User-
  2013.      Defined Variables', which you create yourself in your scripts, 'Global
  2014.      Variables' which are similar to the User-Defined Variables but exist for
  2015.      the duration of the Icom session, 'System Variables', which are similar
  2016.      to the Global Variables, but hold information about your computer system
  2017.      and Intellicomm, BIF Variables, which hold all the current BIF
  2018.      information, Main Setup Variables, which hold all the current INI
  2019.      (INItialization or main setup) information, and Permanent Variables,
  2020.      which are stored on-disk.
  2021.  
  2022.      Each type has a different purpose but the reason for variables of all
  2023.      types is to hold information and thus to avoid specifying CONSTANT data
  2024.      in your script commands.  Anywhere you can specify constant data in a
  2025.      script parameter ('PRINT "John Smith"' prints constant data), you can use
  2026.      a variable ('PRINT myvariable' prints the CONTENTS of the variable
  2027.      'myvariable').  Several examples are given below to show you how to make
  2028.      effective use of all types of variables.
  2029.  
  2030.      4.2  Where you CAN'T use Variables
  2031.  
  2032.      You cannot use variables in place of script GOTO/GOSUB labels.  If you
  2033.      try, you'll get a 'Label not found' error, or worse, Icom will jump to a
  2034.      'label:' you didn't expect it to jump to.  'GOTO myvariable' (if
  2035.      myvariable was a variable) would cause Icom to look for a LABEL called
  2036.      'myvariable:'.  Thus, you cannot use variable names when a GOTO/GOSUB
  2037.      label is expected.
  2038.  
  2039.      4.3  User-Defined Variables
  2040.  
  2041.      User-defined variables are variables you create yourself.  All you do to
  2042.      create a variable is think up a name for it, then use the VARIABLE
  2043.      command to define it in your script:
  2044.  
  2045.  
  2046.  
  2047.  
  2048.      Intellicomm v2.01              SCRTUTOR.DOC                             33
  2049.      
  2050.      
  2051.  
  2052.       VARIABLE myvariable  ;define a variable called 'myvariable'
  2053.  
  2054.      You can also 'assign' something to the variable when you define it by
  2055.      following the variable name with whatever you want to assign to it:
  2056.  
  2057.       VARIABLE myvariable "Please hold this text in myvariable"
  2058.  
  2059.      Once the variable is defined, you can use it in any script command that
  2060.      accepts parameters.  If you printed this variable above:
  2061.  
  2062.       PRINT myvariable
  2063.  
  2064.      ...then PRINT would display this on the screen:
  2065.  
  2066.      Please hold this text in myvariable
  2067.  
  2068.      If you intend to upload your script to a BBS for public distribution,
  2069.      User-Defined Variables also make it easier for users of your script to
  2070.      fill in any required information.  Instead of forcing the user to weed
  2071.      through the entire script and make prompt or response changes, you can
  2072.      define all the necessary information using variables at the TOP of the
  2073.      script where they can easily be found:
  2074.  
  2075.       VARIABLE YourName "John Smith"   ;<-- Put your name here
  2076.       VARIABLE Password "password"     ;<-- Put your password here
  2077.  
  2078.      Placing variables at the TOP of the script makes it much easier for a
  2079.      novice to edit, and it also makes it easier for YOU to maintain your own
  2080.      scripts than it would be to have to weed through the script and change
  2081.      WHEN or SEND commands.
  2082.  
  2083.      4.4  User-Defined Variable Rules
  2084.  
  2085.      User-Defined Variables cannot be used in script commands until you define
  2086.      the variable (give it a name) using the VARIABLE command.  And you must
  2087.      define each variable with the VARIABLE command ONCE and only once (per
  2088.      script ... you can use the same variable name in another script).  After
  2089.      you've defined it, you can change the contents of the variable using
  2090.      ASSIGN and several other commands, but the VARIABLE command should be
  2091.      used only once per variable.  If you do this:
  2092.  
  2093.        variable x 0     ;define variable 'x', store 0 in it
  2094.        variable x 10    ;define variable 'x', store 10 in it
  2095.  
  2096.      Icom will abort the script with a 'Variable exists' error when it finds
  2097.      the second VARIABLE command.  What you would do instead of using the
  2098.      variable command twice is this:
  2099.  
  2100.        variable x 0     ;define variable x, store 0 in it
  2101.        ...
  2102.        assign x 10      ;later in the script if you want to change the
  2103.                         ; value, you use ASSIGN.  This example would store the
  2104.                         ; number 10 in variable x.
  2105.  
  2106.  
  2107.  
  2108.  
  2109.      Intellicomm v2.01              SCRTUTOR.DOC                             34
  2110.      
  2111.      
  2112.  
  2113.      ASSIGN can be used to assign either text or numers to a variable.  
  2114.  
  2115.      You cannot use a script COMMAND as a variable name:
  2116.  
  2117.        variable waitfor   ;duplicates the WAITFOR command
  2118.  
  2119.      If you do this inadvertently, the script will abort with the error:
  2120.      'variable name duplicates a script COMMAND'.  At that point you simply
  2121.      think up a new name (add a 1 to the end of the variable name VARIABLE
  2122.      WAITFOR1 or the like) and you're set.
  2123.  
  2124.      Case is NOT significant in variable names:
  2125.  
  2126.       variable myvariable   ;lowercase
  2127.  
  2128.       assign MYVARIABLE 10  ;uppercase... they're both the same to Icom
  2129.  
  2130.      You can store anything in a variable; numbers, text, symbols, graphics
  2131.      characters ... anything you like (including control characters). 
  2132.      However, the maximum length for data stored in each user-defined variable
  2133.      is 256 characters.
  2134.  
  2135.      User-defined variable names can also be (almost) any name you like.  If
  2136.      you were counting something you might use this:
  2137.  
  2138.       variable count 0   ;define variable 'count', assign 0 to it
  2139.  
  2140.      If you were storing your name, you might use this:
  2141.  
  2142.       variable MyName "John Smith"
  2143.  
  2144.      You CANNOT do this, however:
  2145.  
  2146.       variable My Name "John Smith"  ;note the space in 'My Name'
  2147.  
  2148.      Spaces aren't allowed in variable names.  You can use only letters,
  2149.      numbers (see below), and underscores (_):
  2150.  
  2151.       variable My_Name 10 "John Smith"  ;this is fine with an underscore
  2152.  
  2153.      Further, you cannot BEGIN a variable name with a number: it must start
  2154.      with a non-numeric character.  You can use numbers after the first
  2155.      character, but the very first character of a variable name must be either
  2156.      a letter or an underscore.  These are all valid variable names:
  2157.  
  2158.       VARIABLE count1   ;numbers are okay after the 1st character
  2159.       VARIABLE c1
  2160.       VARIABLE _1      
  2161.  
  2162.      but you cannot use this:
  2163.       
  2164.       VARIABLE 1count   ;cannot start a variable name with a number
  2165.  
  2166.      Icom stores only the first *30* characters of variable names you define
  2167.  
  2168.  
  2169.  
  2170.  
  2171.      Intellicomm v2.01              SCRTUTOR.DOC                             35
  2172.      
  2173.      
  2174.  
  2175.      with the VARIABLE command in its internal table of variable names, and
  2176.      again only checks the first 30 characters when you specify a variable in
  2177.      a script command parameter.  These two variable names are the exact same
  2178.      names to Intellicomm:
  2179.  
  2180.       VARIABLE this_is_very_long_variable_name_1
  2181.       VARIABLE this_is_very_long_variable_name_2
  2182.  
  2183.      The cutoff point, 30 characters, leaves Icom with:
  2184.       
  2185.       VARIABLE this_is_very_long_variable_nam
  2186.  
  2187.      for BOTH of the above variable names.  The above would abort the script
  2188.      with a 'Variable exists' error, since you can't define the same variable
  2189.      twice in the same script.
  2190.  
  2191.      4.5  Why All the Rules?
  2192.  
  2193.      The 30 character limit to variable names is common in programming and
  2194.      script languages (some allow more, many allow less) and the main reason
  2195.      is to conserve memory.  Every name of every variable you create has to be
  2196.      stored in memory in an internal table, so the script processor can find
  2197.      the data when you specify the variable name in a script command.  30
  2198.      characters is a reasonable trade-off between memory conservation and
  2199.      functionality.
  2200.  
  2201.      Intellicomm also has to have some way of knowing whether you're
  2202.      specifying a constant number (1 for example is a constant number), or
  2203.      constant text (surrounded by single or double quotes), or a variable. 
  2204.      The rules outlined above are how it does it.  If a parameter starts with
  2205.      a single or double quote, the script processor knows you're specifying
  2206.      constant text.  If a parameter starts with a number it assumes you're
  2207.      specifying a constant number.  If a parameter has neither a quote nor 0-9
  2208.      as the first character, the script processor assumes you're specifying a
  2209.      variable name and will check its internal tables of variable names to
  2210.      locate the proper data.  Most computer languages use these same rules to
  2211.      separate constants from variables, and numbers from text (strings).
  2212.  
  2213.      Further, other symbols such as +, -, =, <, >, /, *, %, ^, &, |, $, !, [],
  2214.      (), etc., may all be used for various purposes in future expansions of
  2215.      Icom's script language (or are already used), so for maximum
  2216.      compatibility with future releases you can use only a-z, A-Z, _, and 0-9
  2217.      (subject to the rule above about numbers) in your variable names.  By
  2218.      VARIABLE NAMES this doesn't mean the text you specify between the quotes
  2219.      that is assigned to variables.  Between quotes you can use any characters
  2220.      you like (almost... you can't use a real Line Feed or it would put the
  2221.      text on another line... use "^J" [Ctrl-J] for LF).
  2222.  
  2223.      Variable names themselves must never be put in quotes, or Icom will think
  2224.      you're specifying literal text and won't check its table of variable
  2225.      names.  If you did this:
  2226.  
  2227.       PRINT "myvariable"
  2228.  
  2229.  
  2230.  
  2231.  
  2232.      Intellicomm v2.01              SCRTUTOR.DOC                             36
  2233.      
  2234.      
  2235.  
  2236.      the text "myvariable" (minus the quotes) would simply be printed to the
  2237.      screen.  To print the contents of a variable called myvariable, do not
  2238.      use quotes:
  2239.  
  2240.       PRINT myvariable  ;this accesses the CONTENTS of variable 'myvariable'
  2241.  
  2242.      4.6  Using Variables
  2243.  
  2244.      You can use variables in any of Intellicomm's script commands that accept
  2245.      parameters, instead of specifying the parameters literally.  You wouldn't
  2246.      want to have to write five different scripts that all do the same thing,
  2247.      but simply account for slightly different conditions such as a different
  2248.      phone number; so instead of changing one script line then duplicating the
  2249.      entire script, you just use variables, then change the variables, and the
  2250.      script works as is.
  2251.  
  2252.      This command could dial only "Joe's BBS":
  2253.  
  2254.       dial "Joe's BBS"
  2255.  
  2256.      While this script, using variables, could dial any BBS:
  2257.  
  2258.       variable BBSName    ;define variable 'BBSName'
  2259.  
  2260.       boxgets BBSName 20 "Dialing a BBS" "Enter the name of a BBS to dial"
  2261.       dial BBSName
  2262.  
  2263.      We used a new command here that you haven't seen before, called BOXGETS
  2264.      and what it would do (given the parameters above) is accept a 20
  2265.      character string (the 20 following command) in a box that looked like
  2266.      this, but with graphics characters instead of text:
  2267.  
  2268.                        +=| Dialing a BBS |==================+
  2269.                        |                                    |
  2270.                        |   Enter the name of a BBS to dial  |
  2271.                        |                                    |
  2272.                        |   >                                |
  2273.                        |                                    |
  2274.                        +====================================+
  2275.  
  2276.      Whatever was entered in the box would be stored in the variable 'BBSName'
  2277.      (the first parameter in the BOXGETS command).  You then just
  2278.  
  2279.       DIAL BBSName
  2280.  
  2281.      and whatever name was entered in the box would be dialed.
  2282.  
  2283.      When you check the detailed command summary for BOXGETS you'll find all
  2284.      the details, such as how to check to see whether the user pressed the
  2285.      [Esc] key, how to look for a blank string, etc.  You should also look up
  2286.      the DIAL command, since it can be used to simply display the entire BBS
  2287.      Directory, allowing the user to Tag/Dial BBS's... which may be more
  2288.      desirable than what was done above.
  2289.  
  2290.  
  2291.  
  2292.  
  2293.      Intellicomm v2.01              SCRTUTOR.DOC                             37
  2294.      
  2295.      
  2296.  
  2297.      When you apply the same concept we used with the DIAL command above to
  2298.      WHEN, WAITFOR, and all the other script commands, using variables instead
  2299.      of specifying text directly, it allows you to write much more flexible
  2300.      scripts (and you may see more clearly how Icom itself works... it simply
  2301.      loads the BIF information into its variables and executes the same code
  2302.      no matter what BBS is being called).
  2303.  
  2304.      You needn't get variable information from the keyboard; you can get it
  2305.      from a BIF, the Icom main setup data, from a text file on-disk which you
  2306.      can create yourself manually or with other script commands, or you can
  2307.      create variable data on-the-fly based on day of week ($DOW), month
  2308.      ($MONTH), day of month ($DAY), time ($HOUR, $MIN, $SEC), etc.  For
  2309.      example:
  2310.  
  2311.       variable BBS_to_call
  2312.  
  2313.       if $DOW = 1 assign BBS_to_call "Joe's BBS"
  2314.       if $DOW = 2 assign BBS_to_call "Canada Remote System"
  2315.       if $DOW = 3 assign BBS_to_call "Sound Advice" 
  2316.        ; ...etc.
  2317.       DIAL BBS_to_call
  2318.  
  2319.      The first IF statemtent means 'if the day-of-week is equal to Sunday (1),
  2320.      put the text Joe's BBS in variable BBS_to_call'.  If $DOW is equal to 2
  2321.      (Monday), we ASSIGN another BBS name.  I.e. we are ASSIGNing data to the
  2322.      variable on-the-fly, according to the day of the week.
  2323.  
  2324.      You don't have to use variables for the time being, and are actually
  2325.      better off sticking with literal text and numbers until you get the hang
  2326.      of things.  In the beginning the main goal is to write scripts that WORK. 
  2327.      Writing flexible scripts with variables is something you can look into
  2328.      when you're comfortable with the language and have written a few working
  2329.      scripts without variables.  A good way to get practice is to write your
  2330.      scripts with constants first, get them working, and THEN to go and
  2331.      replace one or two of the constants with variables to get the hang of it.
  2332.  
  2333.      4.7  The Life of a Variable
  2334.  
  2335.      User-Defined Variables have a fleeting life most days.  They live (exist
  2336.      in memory) only from the time they are defined with the VARIABLE
  2337.      commmand, and they die (do not exist in memory) when the script ends. 
  2338.      Their use is also limited to the current script.  If you created one
  2339.      script that did this:
  2340.  
  2341.       variable I_Need_This_Number_Elsewhere 10
  2342.  
  2343.      ...then created another script and executed that second script using the
  2344.      SCRIPT command and tried this in the SECOND script:
  2345.  
  2346.       print I_Need_This_Number_Elsewhere
  2347.  
  2348.      then Icom would abort the second script with the error: "Undefined
  2349.      Variable; I_Need_This_Number_Elsewhere".  Variables defined with the
  2350.      VARIABLE command are accessable only from the script in which they were
  2351.  
  2352.  
  2353.  
  2354.  
  2355.      Intellicomm v2.01              SCRTUTOR.DOC                             38
  2356.      
  2357.      
  2358.  
  2359.      created, and only from the point of creation onwards.  You can't do this
  2360.      either:
  2361.  
  2362.       print x           ;don't attempt to use here
  2363.       variable x 10     ; when it hasn't been defined yet
  2364.  
  2365.      Before using a variable the FIRST thing you must do is define it with the
  2366.      VARIABLE command.  Otherwise Icom won't have the name of the variable in
  2367.      its internal table of variable names, and also won't have allocated any
  2368.      memory space to store the variable data.  Variables can be used 'above'
  2369.      the VARIABLE command if you can manage to get the variable defined first. 
  2370.      You can do this for example:
  2371.  
  2372.       gosub define_variables  ;jumps to 'define_variables:', then returns
  2373.       print x                 ; <-- to this line when the subroutine 'returns'
  2374.       exit                    ;exit before we hit 'define_variables' again
  2375.  
  2376.      define_variables:        ;beginning of subroutine 'define_variables'
  2377.       variable x 10           ;define variable 'x' for use above
  2378.       return                  ;end of subroutine 'define_variables'
  2379.  
  2380.      Having variables disappear when a script ends, and only allowing the
  2381.      current script to access them may seem like a limitation at first, but
  2382.      both are actually useful features, and both were done intentionally.  If
  2383.      variables DID exist after the script ended, you'd be tieing up memory on
  2384.      the computer, possibly never to be used again during that Icom session. 
  2385.      By having variables 'die' when the script ends, all the memory they were
  2386.      using is freed up.
  2387.  
  2388.      The other feature; limiting the use of variables to the current script is
  2389.      also very useful.  If you had one script that used a variable called 'x',
  2390.      and you had some important data in 'x' and then called ANOTHER script
  2391.      (using the SCRIPT command, which runs a script from a script) that used
  2392.      the same variable name... you may lose your original value in 'x' if the
  2393.      second script also had an 'x' and modified the value.  If variables
  2394.      didn't work this way you'd constantly have to worry about conflicting
  2395.      variable names in other scripts, that might change your original data...
  2396.      and tracking down such problems would not be easy.
  2397.  
  2398.      4.8  Global Variables
  2399.  
  2400.      For the cases where you DO want certain data to be available from one
  2401.      script to another (for inter-script communication and the like) an
  2402.      'array' of 'global variables' has been provided.  Did your face go pale? 
  2403.      I know it sounds rather complicated, but the Global Variables can be very
  2404.      useful and are well worth knowing about.
  2405.  
  2406.      The 'global' script variables are available from the second Icom starts
  2407.      until you exit the program.  I.e. they hold their data from one job to
  2408.      the next, from one script to the next (with some exceptions... see below)
  2409.      -- for as long as Icom itself remains in memory.  The global variable
  2410.      array is called GlobalStr (Str for 'String'... that means it can hold
  2411.      text OR numbers, as with the User-Defined Variables).
  2412.  
  2413.  
  2414.  
  2415.  
  2416.      Intellicomm v2.01              SCRTUTOR.DOC                             39
  2417.      
  2418.      
  2419.  
  2420.      The term 'array' just means that there are more than one of them: there
  2421.      are 10 in fact.  The first is GlobalStr[0], the second is GlobalStr[1],
  2422.      the third is GlobalStr[2], etc., all the way up to GlobalStr[9] (0-9 = 10
  2423.      variables).  The GlobalStr variables are each 64 characters long, so you
  2424.      can't store anything longer than 64 characters in any one of the 10
  2425.      GlobalStr array members.  If you attempt to store something longer than
  2426.      64 characters, the data will be truncated (cut) at 64 characters by the
  2427.      script processor.
  2428.  
  2429.      Now you're probably wondering about those square brackets, and may be
  2430.      wondering why it's not just GlobalStr1, GlobalStr2, etc.  The reason for
  2431.      that, and the reason for arrays in general in all programming languages,
  2432.      is so that you can use ANOTHER variable to specify WHICH of the global
  2433.      variables you want to access.  Watch this carefully:
  2434.  
  2435.        variable Name_Data 5          ;define Name_Data, assign 5 to it
  2436.  
  2437.        printnc "Enter your name: "   ;print with no carriage return
  2438.        gets GlobalStr[Name_Data] 64  ;get user name, store in GlobalStr[5]
  2439.        print GlobalStr[Name_Data]    ;print GlobalStr[5]
  2440.  
  2441.      (The 64 following the GETS command specifys the maximum number of
  2442.      characters to get.  Remember; each GlobalStr member can hold a maximum of
  2443.      64 characters.)
  2444.  
  2445.      Instead of specifying a constant number in the square brackets of
  2446.      GlobalStr, we used the variable 'Name_Data', which was holding the value
  2447.      of 5.  So, GlobalStr[5] gets the data, since 5 is what 'Name_Data' was
  2448.      holding.  Later in your script you might not remember that you stored the
  2449.      user's name in GlobalStr[5], so it's much easier to just assign the value
  2450.      of 5 to 'Name_Data', and then to use GlobalStr[Name_Data].  It's easier
  2451.      to work with and remember than GlobalStr5 would be, were it not an array.
  2452.  
  2453.      One thing you CANNOT do, at least in this version of the Icom script
  2454.      language is this:
  2455.  
  2456.       GETS GlobalStr[GlobalStr[5]] 64
  2457.  
  2458.      In real programming languages this sort of thing IS legal... and all it
  2459.      would do is access the contents of GlobalStr[5] to get the array offset. 
  2460.      If GlobalStr[5] was holding the value 1, a real programming language
  2461.      would store the result of the GETS command above in GlobalStr[1]. 
  2462.      However once we get into things like that, this becomes possible:
  2463.  
  2464.        GlobalStr[GlobalStr[GlobalStr[GlobalStr[2]]]]
  2465.  
  2466.      ...and that's a little too involved to program the script interpreter to
  2467.      handle at present.  I may get into it in the future, but didn't have time
  2468.      for v2, so you MUST use either a constant number:
  2469.  
  2470.       GlobalStr[0] to GlobalStr[9]
  2471.  
  2472.      Or a user-defined variable (defined with the VARIABLE command) that is
  2473.      HOLDING a number from 0-9:
  2474.  
  2475.  
  2476.  
  2477.  
  2478.      Intellicomm v2.01              SCRTUTOR.DOC                             40
  2479.      
  2480.      
  2481.  
  2482.       variable globalstr_offset 9  ;assign 9 to globalstr_offset
  2483.  
  2484.       GlobalStr[globalstr_offset]  ;GlobalStr[9]
  2485.  
  2486.      You MUST NOT USE SPACES anywhere from GlobalStr[ to the closing ].  These
  2487.      are programming errors:
  2488.  
  2489.       GlobalStr [offset]       ;space between GlobalStr and [
  2490.       GlobalStr[ offset ]      ;spaces in the brackets
  2491.       GlobalStr[ 5 ]           ;spaces in the brackets
  2492.  
  2493.      It must be kept together as a single unit, with no spaces, and this is
  2494.      the correct way to specify the three example errors above:
  2495.  
  2496.       GlobalStr[offset]
  2497.       GlobalStr[offset]
  2498.       GlobalStr[5]
  2499.  
  2500.      4.9  Using Global Variables
  2501.  
  2502.      Until you become more familiar with the other script commands and
  2503.      concepts it's difficult to demonstrate any advanced use of these
  2504.      variables.  But their purpose is threefold: (1) to allow inter-script
  2505.      communication (access to the same data by multiple scripts... which isn't
  2506.      possible with the User-Defined Variables), (2) to allow 'command line
  2507.      parameters' to be passed to scripts from DOS (the /scr: command line
  2508.      switch) BIFs, Custom Commands, and other scripts (the parameters are
  2509.      stored in the GlobalStr array), and (3) basic array usage, which, in real
  2510.      programming languages is indespensible.
  2511.  
  2512.      The main idea behind an array is to use ANOTHER variable as an index to
  2513.      access members of the array.  You can start the index variable
  2514.      ('Name_Data' in the example above was the index variable) at 0, then add
  2515.      one to the index variable whenever you need another global variable:
  2516.  
  2517.        variable gindex 0                     ;start at 0
  2518.  
  2519.        assign GlobalStr[gindex] "Some data"  ;goes in GlobalStr[0]
  2520.        inc gindex                            ;INCrement: gindex = gindex + 1
  2521.  
  2522.         ; ... later in your script
  2523.  
  2524.        assign GlobalStr[gindex] "More data"  ;goes in GlobalStr[1]
  2525.        inc gindex                            ;gindex now equals 2... ready
  2526.                                              ; for the NEXT bit of data
  2527.  
  2528.      Or you can use a 'loop' to clear all the variables in the array, or
  2529.      combined with other functions can quickly copy data from various sources
  2530.      into the array.  A 'loop' simply means that Icom will execute the
  2531.      commands between WHILE and ENDWHILE (below) as long as the condition
  2532.      specified in the WHILE remains true. I.e. as long as the value in
  2533.      'offset' is less than or equal to the number 9 (9 being the GlobalStr
  2534.      array limit... GlobalStr[9] is the end of the array).  Since we start
  2535.      with 'offset' at 0, and add one to it at the bottom of the loop, the
  2536.  
  2537.  
  2538.  
  2539.  
  2540.      Intellicomm v2.01              SCRTUTOR.DOC                             41
  2541.      
  2542.      
  2543.  
  2544.      commands in the loop will be executed 10 times each.  More details on
  2545.      loops can be found in the WHILE Detailed Command Summary.  Here's a quick
  2546.      example:
  2547.  
  2548.        variable offset 0           ;define variable 'offset', set to 0
  2549.  
  2550.        while offset <= 9           ;while offset is less than or equal to 9
  2551.         printnc "Enter item "      ;These five lines in the loop will be
  2552.         printnc offset             ; executed UNTIL 'offset' is greater than
  2553.         printnc ": "               ; 9.  When 'offset' is 10, we exit the
  2554.         gets GlobalStr[offset] 40  ; loop and continue below ENDWHILE
  2555.         inc offset                 ;increment: offset = offset + 1
  2556.        endwhile                    ;end of the 'loop'
  2557.  
  2558.        print "Here is what you entered:"
  2559.        assign offset 0             ;It's very important to reset 'offset' to 0
  2560.        while offset <= 9           ; or else we wouldn't enter this 'loop' at
  2561.         print GlobalStr[offset]    ; all. Remember it's now holding the number
  2562.         inc offset                 ; *10* due to the loop above, and 10 is NOT
  2563.        endwhile                    ; less than or equal to nine.
  2564.  
  2565.      Loops and arrays were invented to avoid having to do this:
  2566.  
  2567.        printnc "Enter item 0: "
  2568.        gets GlobalStr[0] 40
  2569.        printnc "Enter item 1: "
  2570.        gets GlobalStr[1] 40
  2571.        printnc "Enter item 2: "
  2572.        gets GlobalStr[2] 40
  2573.            ;this would continue right up to GlobalStr[9] to accomplish
  2574.            ; the same thing the FIRST loop above did.
  2575.  
  2576.        print "Here is what you entered:"
  2577.        print GlobalStr[0]
  2578.        print GlobalStr[1]
  2579.        print GlobalStr[2]
  2580.            ;this would also continue right up to GlobalStr[9] to accomplish
  2581.            ; what the SECOND loop above did.
  2582.  
  2583.      Of course, the same principle can be applied to ANY script command (any
  2584.      commmand that takes a parameter), and GlobalStr isn't limited to GETS and
  2585.      PRINT and ASSIGN.  You can use this global array variable anywhere your
  2586.      imagination takes you, with any script command that takes parameters.
  2587.  
  2588.      4.10  Passing Parameters to Scripts
  2589.  
  2590.      When parameters are passed to a script, either from the BIF:
  2591.  
  2592.       | Your Logon Name> @DEMO parm1 parm2     Name . . . . . . st Name? «   |
  2593.                         ^^^^^^^^^^^^^^^^^
  2594.      or from a Custom Command:
  2595.  
  2596.       | 12  Custom Command/Run script        |   CC: @DEMO parm1 parm2 ...   |
  2597.                                                     ^^^^^^^^^^^^^^^^^
  2598.  
  2599.  
  2600.  
  2601.  
  2602.      Intellicomm v2.01              SCRTUTOR.DOC                             42
  2603.      
  2604.      
  2605.  
  2606.      or from a script via the SCRIPT command:
  2607.  
  2608.       SCRIPT "DEMO.SCR" "parm1" "parm2" variable_parm
  2609.  
  2610.      or from the ICOM.EXE /scr: command line option:
  2611.  
  2612.       ICOM.EXE /scr:"DEMO.SCR parm1 parm2"
  2613.  
  2614.      the first parameter is stored in GlobalStr[1], the second in
  2615.      GlobalStr[2], then GlobalStr[3], and so on.  The quotes are needed when
  2616.      specifying parameters in the /scr: command line option (see above) to
  2617.      keep it all together.  Otherwise DOS separates the parameters due to the
  2618.      spaces between parameters, and they look like separate 'switches' to
  2619.      Icom.
  2620.  
  2621.      Note that when using the SCRIPT command, you can pass VARIABLES instead
  2622.      of literal strings (variable_parm above assumes the script had a variable
  2623.      called variable_parm), which simply has the effect of copying the
  2624.      variable data into the GlobalStr array.  As mentioned previously the
  2625.      regular user-defined variables are available ONLY within the script
  2626.      they're defined in.  By using variables as parameters in a SCRIPT
  2627.      command, the called script could then access the data by looking in
  2628.      GlobalStr.  You can also just copy the data explicitly, if you like,
  2629.      instead of passing parameters:
  2630.  
  2631.        assign GlobalStr[1] "parm 1"       ;copy 'parm 1' into GlobalStr[1]
  2632.        assign GlobalStr[2] "parm 2"
  2633.        assign GlobalStr[3] variable_parm
  2634.        SCRIPT "DEMO.SCR"
  2635.  
  2636.      The above has the same effect as the previous example, which specified
  2637.      parameters directly in the SCRIPT command.
  2638.  
  2639.      NOTE: When passing parameters from a BIF or Custom Command, Icom
  2640.      separates the parameters by looking for space " " characters.  As soon as
  2641.      a space is found, the data following the space goes in the next GlobalStr
  2642.      member.  If you wish to pass a single parameter which CONTAINS a space,
  2643.      you must put the parameter in quotes (similar to DOS command line
  2644.      options):
  2645.  
  2646.      | 12  Custom Command/Run script        |   CC: @DEMO "parm 1" "parm 2"  |
  2647.                                                     ^^^^^^^^^^^^^^^^^^^^^^^
  2648.      The two parameters specified above would go in GlobalStr[1] and
  2649.      GlobalStr[2] (the quotes are stripped before storing the parameter(s) in
  2650.      GlobalStr).
  2651.  
  2652.      Alternatively you could just put quotes around ALL the parameters (to
  2653.      have them all stored in GlobalStr[1]), then use the STRITEM command to
  2654.      get the individual parameters yourself:
  2655.  
  2656.      | 12  Custom Command/Run script        |   CC: @DEMO "parm1 parm2"      |
  2657.                                                     ^^^^^^^^^^^^^^^^^^^    
  2658.      From inside the script you'd do this to get the individual parameters:
  2659.  
  2660.  
  2661.  
  2662.  
  2663.      Intellicomm v2.01              SCRTUTOR.DOC                             43
  2664.      
  2665.      
  2666.  
  2667.       variable parm1
  2668.       variable parm2
  2669.  
  2670.        ;GlobalStr[1] would be holding "parm1 parm2" (no quotes) given the
  2671.        ; Custom Command example above
  2672.  
  2673.       STRITEM parm1 GlobalStr[1] 1 ;get item 1 from GlobalStr[1], put in parm1
  2674.       STRITEM parm2 GlobalStr[1] 2 ;get item 2 from GlobalStr[1], put in parm2
  2675.  
  2676.      Please see the Detailed Command Summary for more information on STRITEM.
  2677.  
  2678.      4.11  Checking the Number of Passed Parameters
  2679.  
  2680.      If you were paying close attention earlier, you might be wondering why
  2681.      the parameters don't start at GlobalStr[0] ... since GlobalStr[0] is the
  2682.      FIRST variable in the array ... not GlobalStr[1].  The reason for that is
  2683.      to allow you to quickly check how many (if any) parameters were passed to
  2684.      your script.  The script processor stores the total number of parameters
  2685.      (a number from 0 to 9) passed to your script in GlobalStr[0].  So, if
  2686.      your script REQUIRED 3 parameters to be passed to it, and they weren't
  2687.      all specified, you'd know about it quickly:
  2688.  
  2689.       if GlobalStr[0] <> 3   ;if GlobalStr[0] is not equal to 3
  2690.        msgwind "Hey, you were supposed to specify 3 parameters!"
  2691.        return
  2692.       endif
  2693.  
  2694.       print "Thanks for the 3 parameters.  You specified:"
  2695.       print GlobalStr[1]
  2696.       print GlobalStr[2]
  2697.       print GlobalStr[3]
  2698.       return
  2699.  
  2700.      It's as easy as 0-1-2 (or 1-2-3, whichever you prefer).  Of course, this
  2701.      GlobalStr[0] business is something you'll have to keep in mind (a) if
  2702.      you're storing anything important in GlobalStr[0] and (b) if you use the
  2703.      SCRIPT command to call another script from your existing script.  I.e. if
  2704.      anything important is stored in GlobalStr[0] (your own data... Icom
  2705.      doesn't care what's in GlobalStr[0]) you'll lose it if you execute a
  2706.      SCRIPT command from within the current script.  You can overcome any
  2707.      problems by doing this:
  2708.        
  2709.        variable some_variable  
  2710.  
  2711.        assign GlobalStr[0] "Important data" ;holding something important
  2712.        ...                                  ;meanwhile, later in the script...
  2713.        assign some_variable GlobalStr[0]    ;save GlobalStr[0]
  2714.        script "ANOTHER.SCR"                 ;run ANOTHER.SCR
  2715.        assign GlobalStr[0] some_variable    ;restore GlobalStr[0]
  2716.  
  2717.      Note that even though you didn't PASS any parameters to ANOTHER.SCR, the
  2718.      script processor would still store the number 0 in GlobalStr[0], to tell
  2719.      ANOTHER.SCR that no parameters were passed.  Of course, if you DID pass
  2720.      parameters to ANOTHER.SCR, then GlobalStr[1] and possibly GlobalStr[2],
  2721.  
  2722.  
  2723.  
  2724.  
  2725.      Intellicomm v2.01              SCRTUTOR.DOC                             44
  2726.      
  2727.      
  2728.  
  2729.      etc., would also be lost, depending on how many parameters you specified. 
  2730.      If you pass 9 parameters to a script then the entire GlobalStr array is
  2731.      overwritten with your parameters.
  2732.  
  2733.      Now that you know this though, it should be no problem to simply save any
  2734.      important data in GlobalStr before executing the SCRIPT command, then to
  2735.      restore the information after the SCRIPT command as illustrated above. 
  2736.  
  2737.      TIP: If you DO have something important to hang onto (and it must be
  2738.      'globally' available to other scripts), you're much better off storing it
  2739.      in GlobalStr[9] than you are storing it in GlobalStr[0].  It's not likely
  2740.      that 9 parameters would ever be passed to a script, so keep your
  2741.      important global data at the high end of GlobalStr, and keep the lower
  2742.      portion open for passing parameters.  Data stored in GlobalStr[9],
  2743.      GlobalStr[8] probably all the way down to GlobalStr[5] would most likely
  2744.      remain untouched throughout the entire Intellicomm session, from one job
  2745.      to the next, from one script to the next, etc.
  2746.  
  2747.      If the data won't be needed outside the current script though, there's no
  2748.      need to use GlobalStr at all... you can just use the regular variables
  2749.      (defined with the VARIABLE command), which are protected when you run
  2750.      another script.
  2751.  
  2752.      4.12  System Variables
  2753.  
  2754.      You can also obtain various system information to use with script
  2755.      commands and to put in your variables, such as the system date and time,
  2756.      the current up/download directories and protocols, and lots of other
  2757.      useful information.  System variables begin with a dollar sign ($) and
  2758.      can be used in any Icom script command that accepts parameters:
  2759.  
  2760.       print $DATE
  2761.  
  2762.      This command prints today's date to the screen (in the date format
  2763.      defined by the user in the Icom main setup... usually MM/DD/YY).  System
  2764.      Variables increase flexibility and allow you to write scripts for use by
  2765.      others, since you needn't use constant data.  For example, DOWNLOAD "Z"
  2766.      was used to demonstrate the download command earlier, but that's
  2767.      inflexible and forces Zmodem.  With Icom, everyone defines the upload and
  2768.      download protocols they prefer to use in their BIFs, so instead of using
  2769.      "Z", you can use a System Variable:
  2770.  
  2771.       download $DL_PROTOCOL
  2772.  
  2773.      Whatever protocol the user had defined as the file download protocol (in
  2774.      whatever BIF was currently loaded) would then be called to carry out the
  2775.      download -- even if it was an external protocol.  You can also use System
  2776.      Variables to *check* settings if need be:
  2777.  
  2778.       if $DL_PROTOCOL <> "Z"   ;not Zmodem?
  2779.        print "Sorry, this script requires use of Zmodem.  Please set your"
  2780.        pause "BIF up to use Zmodem and re-try.  Press a key..."
  2781.        exit
  2782.       endif
  2783.  
  2784.  
  2785.  
  2786.  
  2787.      Intellicomm v2.01              SCRTUTOR.DOC                             45
  2788.      
  2789.      
  2790.  
  2791.      You could also just ASSIGN $DL_PROTOCOL "Z" to have your script change
  2792.      it, instead of aborting the script... but if you do that, make sure you
  2793.      save the ORIGINAL value of $DL_PROTOCOL in a user-defined variable, and
  2794.      restore the value before your script ends.
  2795.  
  2796.      Please see the System Variable Appendix and/or the SCRIPT COMMANDS AT A
  2797.      GLANCE section of SCRIPT.DOC for a listing of all the System Variables.
  2798.  
  2799.      4.13  BIF Variables
  2800.  
  2801.      BIF Variables start with an asterisk (*), are then followed by the BIF
  2802.      'section' in square brackets ([G] = General screen, [L] = Logon screen,
  2803.      etc) then the "tag" of the BIF item.  Example:
  2804.  
  2805.      WHEN *[L]namp SEND *[L]namc   ;BIF Logon name prompt/command (response)
  2806.  
  2807.      You can access (and change, if necessary) any of the BIF variables in
  2808.      this way.  All the BIF sections and tags are documented in SCRIPT.DOC in
  2809.      the "BIF Variables" section.
  2810.  
  2811.      NOTE: Until Icom dials or connects to a BBS, and after it disconnects,
  2812.      the BIF data is unpredictable and could be that of any BBS (check the
  2813.      $BIF_NAME System Variable to get the filename of the currently loaded
  2814.      BIF, if any).  You can use the LOADBIF command to load a specific BIF
  2815.      into memory if you need specific BIF data.
  2816.  
  2817.      4.14  Main Setup and Environment Variables
  2818.  
  2819.      You can also access (and change) any of the Icom main setup by specifying
  2820.      an asterisk (*) followed by a main setup "tag".  Example:
  2821.  
  2822.       ASSIGN *dtime 60  ;60 second 'Timeout' when dialing
  2823.  
  2824.      Each variable holds a specific piece of information, in a specific FORMAT
  2825.      and you shouldn't use any of these variables before reading the "Main
  2826.      Setup Variables" section in SCRIPT.DOC.
  2827.  
  2828.      Note that these settings are stored on-disk in ICOM.INI by default, which
  2829.      is loaded into memory (the Main Setup Variables) when Icom initializes.
  2830.      If necessary you load and save various .INI files using the LOADINI and
  2831.      SAVEINI commands.
  2832.  
  2833.      4.15  Environment Variables
  2834.  
  2835.      You can also access variables in the ICOM.EXE program 'environment'
  2836.      (where the DOS PATH is stored, and any other environment variables the
  2837.      user had defined with the DOS 'SET' command) using GETENV / SETENV.  Each
  2838.      of these commands is described in the Detailed Command Summary section of
  2839.      SCRIPT.DOC.
  2840.  
  2841.  
  2842.  
  2843.  
  2844.      Intellicomm v2.01              SCRTUTOR.DOC                             46
  2845.      
  2846.      
  2847.  
  2848.              5.  PERMANENT VARIABLES: INTRODUCTION TO FILE INPUT/OUTPUT
  2849.  
  2850.  
  2851.      Permanent variables exist even after the computer is turned off.  They're
  2852.      not stored in memory as the variables discussed above are; they're stored
  2853.      on-disk.  Through the use of the script file Input/Output (file I/O)
  2854.      commands you can have your scripts 'remember' things forever... or at
  2855.      least until disk failure.  Likely candidates to become "permanent"
  2856.      variables are any user-configurable settings your script must remember
  2857.      from one run to the next.
  2858.  
  2859.      You don't have to know anything about disks, or how DOS works with files
  2860.      to use the file I/O commands.  If you can PRINT data on your monitor with
  2861.      a script, then you're just a couple of steps away from doing the
  2862.      equivalent of PRINTing data to a file using the file I/O commands.
  2863.  
  2864.      If you're nervous about using the disk, and think you might screw your
  2865.      whole hard drive up accidentally, relax.  Using the script file I/O
  2866.      commands is no less "dangerous" than starting up your word processor,
  2867.      typing a letter, and saving it on-disk using the proper filename
  2868.      ('proper' meaning that you don't inadvertently type the wrong filename
  2869.      frequently and overwrite imporant files by accident).  If you can do that
  2870.      without worrying about losing important data on your disks, then you're
  2871.      fully qualified to use the script file I/O commands: All you need to know
  2872.      about files, as with your Text Editor, is the D:\PATH\FILENAME.EXT of the
  2873.      file.  They do nothing you can't already do from your word processor or
  2874.      text editor (except to automate the task of creating and maintaining the
  2875.      files... and to allow you to do it from a script instead of having to
  2876.      start up the Text Editor and do it manually).
  2877.  
  2878.      DOS takes care of all the nitty grittys as far as disk use goes (the
  2879.      script file I/O commands simply pass intructions to DOS, after verifying
  2880.      them) and DOS knows what it's doing.  It won't *let* you screw up and
  2881.      unintentionally overwrite other files on your disk, no matter how hard
  2882.      you try.  To overwrite existing data on-disk, you must be quite specific
  2883.      about your intentions.  You can't open one file, and inadvertently write
  2884.      to another ... no more than you can load a specific file into your Text
  2885.      Editor and inadvertently end up overwriting some other file on-disk by
  2886.      "typing too much".  It just doesn't happen.  If you add to a file (any
  2887.      file) DOS uses *free* disk space to save the new data, and it will never
  2888.      overwrite the data in another file to expand an existing file:  That's
  2889.      what "Disk Full" messages are for... and you'll get a "Disk Full" error
  2890.      using the File I/O commands as well, if there's no *free* space on disk,
  2891.      and you attempt to add new data to a file.
  2892.  
  2893.      And luckily, no rocket science is required:  (1) You first open the file
  2894.      you're interested in, by specifying its filename; and this is why it was
  2895.      said above that you cannot UNINTENTIONALLY overwrite files on your hard
  2896.      drive ... unless you're a klutz with filenames; (2) you then read or
  2897.      write to the file line by line, transferring the information from the
  2898.      file into your variables (to memory), or from variables/constants into
  2899.      the file; (3) then you close the file.  It's simple!  Here's a quick
  2900.      example:
  2901.  
  2902.  
  2903.  
  2904.  
  2905.      Intellicomm v2.01              SCRTUTOR.DOC                             47
  2906.      
  2907.      
  2908.  
  2909.       variable f1              ;variable used as the file "handle".  You'll
  2910.                                ; note below that FOPEN, FPUTS, and FCLOSE
  2911.                                ; all use this variable
  2912.  
  2913.       FOPEN f1 "TEST.DAT" "w"  ;open TEST.DAT for "w"riting; overwrites any 
  2914.                                ; files on-disk of the same name
  2915.       FPUTS f1 "John Smith"    ;write this text to the file, following each
  2916.       FPUTS f1 "123 Anystreet" ; fputs with a Carriage Return/Line Feed.  To
  2917.       FPUTS f1 "Anytown, Ont." ; write WITHOUT adding a CR/LF, use fputsnc
  2918.       FCLOSE f1                ;close the file
  2919.  
  2920.      If you executed the above script, you'd end up with a text file on-disk
  2921.      called TEST.DAT (in the current directory, whatever that happened to be)
  2922.      that contained the following:
  2923.  
  2924.      John Smith
  2925.      123 Anystreet
  2926.      Anytown, Ont.
  2927.  
  2928.      The only 'danger' involved (when opening a file for "w"riting, as we did
  2929.      above) is in specifying the proper filename... just as you make sure to
  2930.      specify the proper filename when you save a file on-disk from your word
  2931.      processor.  And just as in your word processor, if you don't specify a
  2932.      drive and path (D:\PATH\) with the FILENAME.EXT, the file is created in
  2933.      the current directory.  By ALWAYS specifying the full
  2934.      D:\PATH\FILENAME.EXT of the files you FOPEN, you'll never have to worry
  2935.      about inadvertently overwriting useful files.  In many of the examples
  2936.      below, the D:\PATH\ is omitted for brevity, but in a real script you must
  2937.      ALWAYS either use a CHDIR command, or specify the full
  2938.      D:\PATH\FILENAME.EXT.  Either of these are fine:
  2939.  
  2940.       CHDIR "C:\SOMEDIR"
  2941.       FOPEN f1 "SOMEFILE.EXT" "w"
  2942.  
  2943.       FOPEN f1 "C:\SOMEDIR\SOMEFILE.EXT" "w"
  2944.  
  2945.      The latter is the safest, since a CHDIR command will fail if the
  2946.      directory doesn't exist... and were that the case, the first FOPEN would
  2947.      simply create SOMEFILE.EXT in the current directory, *overwriting* any
  2948.      file of the same name that happened to exist in whatever directory you
  2949.      were in at the time.  Once you FOPEN a file for "w"riting, you
  2950.      immediately destroy the contents of any file of the same name.  So make
  2951.      sure you get the filename right when you FOPEN for "w"riting!
  2952.  
  2953.      5.1  FOPEN 'Modes'
  2954.  
  2955.      You can FOPEN a file for reading (no writing... the file must exist),
  2956.      writing (no reading... the file will be created and will overwrite any
  2957.      file of the same name) or 'appending' (add to the end of an existing
  2958.      file, or create the file if it doesn't exist).  And once you master file
  2959.      I/O, you can even open a file for reading AND writing, if the need arises
  2960.      (more on this later).  The "w" above in the FOPEN command (after the
  2961.      filename) specifies writing only, this mode overwrites any file of the
  2962.      same name that exists in the current directory; "r" specifies reading
  2963.  
  2964.  
  2965.  
  2966.  
  2967.      Intellicomm v2.01              SCRTUTOR.DOC                             48
  2968.      
  2969.      
  2970.  
  2971.      only, and "a" specifies appending (create or add to).
  2972.  
  2973.      5.2  The File Handle
  2974.  
  2975.      The variable 'f1' is specified in all of the file commands to identify
  2976.      WHICH file you want to operate on.  Several files can be FOPENed at the
  2977.      same time -- usually for the purpose of reading data from one file and
  2978.      writing it to another -- and it would be tedious to have to specify the
  2979.      filename every time:
  2980.  
  2981.       FOPEN "test.dat" "w"
  2982.       FPUTS "test.dat" "John Smith"
  2983.        ...
  2984.       FCLOSE "test.dat"
  2985.  
  2986.      And it would be even more tedious were you operating on a file called
  2987.      "C:\MYDIR\SUBDIR1\SUBDIR2\SOMEFILE.TXT".  So instead of forcing you to
  2988.      specify the filename every time you operate on an open file, FOPEN takes
  2989.      a variable and then lets you use that variable name from then on (until
  2990.      after you FCLOSE the file) to 'refer' to the filename you specified in
  2991.      the FOPEN command.
  2992.  
  2993.      The variable name you choose for the file handle is up to you, and 'f1'
  2994.      was just an example.  You could call the file handle variable 'test_dat'
  2995.      (or any other legal variable name) if you wanted to.
  2996.  
  2997.      Since you can FOPEN several files at a time, whenever you FPUTS (write
  2998.      to), or FCLOSE a file, the script processor has to know *which* file you
  2999.      want to operate on.  FOPEN stores a number called a file "handle" in the
  3000.      variable you specify before the filename, and by specifying that same
  3001.      variable in all the file commands later, the script processor always
  3002.      knows which open file you want to deal with.  Simple!
  3003.  
  3004.      If you ran the example script above, you could then load the file
  3005.      TEST.DAT into your Text Editor and read it or modify it just like any
  3006.      other text file.  Or, at some later point on some later day you could
  3007.      load the information and use it in a script:
  3008.  
  3009.        variable Name          ;define some variables
  3010.        variable Address
  3011.        variable City
  3012.        variable f
  3013.  
  3014.        FOPEN f "test.dat" "r" ;open for "r"eading
  3015.        FGETS Name f           ;read first line, store in 'Name'
  3016.        print Name             ; this prints John Smith
  3017.        FGETS Address f        ;read next line, store in 'Address'
  3018.        print Address          ; this prints 123 Anystreet
  3019.        FGETS City f           ;read next line, store in 'City'
  3020.        print City             ; this prints Anytown, Ont.
  3021.        FCLOSE f
  3022.  
  3023.      FGETS reads data from a file, and stores it in a variable (or variables
  3024.      in this case; Name, Address, and City).  Note that FGETS takes the file
  3025.  
  3026.  
  3027.  
  3028.  
  3029.      Intellicomm v2.01              SCRTUTOR.DOC                             49
  3030.      
  3031.      
  3032.  
  3033.      handle (the variable 'f' holds the file handle) as the SECOND parameter. 
  3034.      As with all script commands, the variable you're ASSIGNING data to is
  3035.      always the first parameter specified.  FPUTS takes the file number as the
  3036.      first parameter because it doesn't assign anything to the variable, and
  3037.      also to allow you to FPUTS more than one item:
  3038.  
  3039.        variable some_text "some text"
  3040.        FPUTS f "This is " some_text " to FPUTS"
  3041.  
  3042.      After looking at the prior example, you may be wondering how FGETS knows
  3043.      what to store in which variable... How it knows to put the name in
  3044.      'Name', the address in 'Address' and so on.  But the fact is it doesn't:
  3045.      we do.  All FGETS does is to read the file line by line.  The first call
  3046.      to FGETS reads the first line... the second reads the second line, the
  3047.      third reads the third line.  WE know that the first line contains the
  3048.      Name, and the second line contains the Address, etc., since we created
  3049.      the data file earlier in the first example.  So we knew enough to call
  3050.      the variables 'Name', 'Address' and 'City' since that's what's in the
  3051.      data file.  You 'could' do this, though it wouldn't make much sense:
  3052.  
  3053.        FOPEN f "test.dat" "r"  ;open for reading
  3054.        FGETS f City            ;read first line, store in 'City'
  3055.        print City              ; <-- this still prints John Smith
  3056.        FGETS f Name            ;read next line, store in 'Name'
  3057.        print Name              ; <-- this still prints 123 Anystreet
  3058.        FGETS f Address         ;read next line, store in 'Address'
  3059.        print Address           ; <-- this still prints Anytown, Ont.
  3060.        FCLOSE f
  3061.  
  3062.      This serves to prove that the names of variables are irrelevant to the
  3063.      script processor...  You can call a variable anything you like, and you
  3064.      can give ANY variable to ANY script command as a parameter.  Whatever
  3065.      name you give the variable (and the variables you choose to use as script
  3066.      parameters) will only be meaningful to you ... and possibly to other
  3067.      human-types.  The script processor will store anything, anywhere, with no
  3068.      regard to whether the actual variable name used 'makes sense'.
  3069.  
  3070.      So how does FGETS 'remember' which line to get out of a file next?
  3071.  
  3072.      The file I/O functions keep track of the "current position(s)" of all
  3073.      open files (until FCLOSE is called) with what is known as the "file
  3074.      pointer".  FGETS and FPUTS simply move this pointer whenever you read or
  3075.      write to the file.
  3076.  
  3077.      If you use FPUTS, the data is written to the file (at the 'current'
  3078.      pointer position) and the file pointer is then moved ahead by however
  3079.      many bytes were written (plus two bytes for the Carriage Return/Line Feed
  3080.      [CR/LF] FPUTS adds to the end of each line).  The next time FPUTS is
  3081.      called, it simply writes at the position of the file pointer and then
  3082.      moves the pointer ahead again.
  3083.  
  3084.      The same happens with FGETS, and the file pointer is moved ahead by
  3085.      however many bytes were in the line you just read.  The next time you
  3086.      call FGETS it reads from the position of the pointer, then moves the
  3087.  
  3088.  
  3089.  
  3090.  
  3091.      Intellicomm v2.01              SCRTUTOR.DOC                             50
  3092.      
  3093.      
  3094.  
  3095.      pointer again to get ready for the next FGETS.
  3096.  
  3097.      FGETS is designed to read a single line of a text file, and it knows the
  3098.      end of the line by the Line Feed written at the end of each line by
  3099.      FPUTS.  As soon as FGETS finds a LF, it stops reading the file, and moves
  3100.      the pointer ahead by however many bytes it read, to get ready for the
  3101.      next FGETS.  The carriage return and line feed at the end of each line in
  3102.      the file are stripped by FGETS before it stores the data in the variable,
  3103.      since you'll rarely (if ever) want them.
  3104.  
  3105.      If you open a file for "a"ppending (add to the end of the file), FOPEN
  3106.      automatically moves the file pointer to the end of the file after it's
  3107.      opened, so that the firs time you FPUTS to the file, the data goes
  3108.      *after* any data already in the file (however, Ctrl-Z characters at the
  3109.      end of the file, if any, are overwritten.  FOPEN automatically checks for
  3110.      Ctrl-Z's and moves the file pointer back so that the first FPUTS will
  3111.      overwrite any existing Ctrl-Z's).
  3112.  
  3113.      You can also read from and write to a file character by character by
  3114.      using FPUTC and FGETC, which both move the file pointer ahead by one
  3115.      character (one byte) per read/write.  And you can FPUTS without adding a
  3116.      CR/LF by using FPUTSNC (NC for 'N'o 'C'arriage return).
  3117.  
  3118.      If you're wondering whether FGETS and FPUTS keep *separate* file
  3119.      pointers, and keep track of where data will be both read from and written
  3120.      to next, the answer is no.  Reading from, and writing to the SAME file,
  3121.      with a single FOPEN, is simply not something you'll need to do very
  3122.      often.  You 'can' do it, and we'll be discussing this below, but in all
  3123.      the examples so far we have EITHER opened a file for "r"eading (which
  3124.      means that writing is prohibited and if you attempt to FPUTS to the file,
  3125.      the FPUTS is ignored) or "w"riting (which means that FGETS [reading] is
  3126.      prohibited and FGETS is ignored).  To both read and write, you must open
  3127.      the file in a special way, and it's really not something you're likely to
  3128.      have to do.  What you'll usually do is FCLOSE the file, then FOPEN it
  3129.      again in another 'mode' to switch from reading to writing.  And FOPEN
  3130.      automatically moves the file pointer back to the beginning (or end, if
  3131.      opened in "a"ppend mode) of the file, so there's no need for separate
  3132.      read/write file pointers.
  3133.  
  3134.      NOTE 1: As mentioned earlier, unless you specify a path with the filename
  3135.      in FOPEN, the file is created (or searched for, if opened for reading) in
  3136.      the *current directory*.  The DOS PATH does not apply when FOPEN is
  3137.      looking for a file to open.  Thus, you should always specify full
  3138.      pathnames when using FOPEN.  You can use the $HOME_DIR System Variable to
  3139.      create files in the Icom home directory (where ICOM.EXE is), if your
  3140.      script will be used by others.  The various Icom system directories
  3141.      ALWAYS have a trailing slash (even if you change a System Variable in
  3142.      your script and forget to add the slash, one is automatically added), so
  3143.      you can simply append filenames to these directories.  Examples:
  3144.  
  3145.       FOPEN f "c:\mydir\some.dat" "a"  ;create or 'a'ppend to
  3146.       FOPEN f "a:\catalog.txt" "r"     ;open for 'r'eading
  3147.  
  3148.       variable test_dat $HOME_DIR "test.dat"
  3149.  
  3150.  
  3151.  
  3152.  
  3153.      Intellicomm v2.01              SCRTUTOR.DOC                             51
  3154.      
  3155.      
  3156.  
  3157.        ;$HOME_DIR would contain C:\ICOM\ or the like.  Note how we assigned
  3158.        ; multiple items to 'test_dat' with a single VARIABLE command.  The
  3159.        ; end-result in variable 'test_dat' would be C:\ICOM\test.dat or the
  3160.        ; like.
  3161.  
  3162.       FOPEN f test_dat "w"         ;fopen "C:\ICOM\test.dat" "w"
  3163.  
  3164.        ;you can also open 'devices' in the same manner:
  3165.  
  3166.       FOPEN f "PRN" "w"            ;open device 'PRN' (printer) for writing
  3167.       FOPEN f $PRN "w"             ;ditto, but use the device the user has
  3168.                                    ; defined in the Icom main setup
  3169.       FPUTS "This goes to the printer!"
  3170.       FCLOSE f                     ;you still have to FCLOSE
  3171.  
  3172.      However, do not attempt to open a COM port that Icom is using!  [It's
  3173.      okay if Icom isn't using it, and the port goes to a printer though.]  The
  3174.      file I/O functions are not very well suited to communications in any case
  3175.      (it would work though, if you tried it on a port that Icom wasn't already
  3176.      using), and you're much better off using the PORT command (open a new COM
  3177.      port), then using SEND and the other COM-related commands, which were
  3178.      designed for efficient port I/O.
  3179.  
  3180.      NOTE 2: There is a limit in the number of files you can open with FOPEN
  3181.      (before calling FCLOSE, that is.  You can open as many files as you like
  3182.      if you FCLOSE each file when you're done with it).  The script processor
  3183.      can accomodate up to ten open files at a time... The eleventh FOPEN with
  3184.      no FCLOSE (i.e. trying to open eleven files at the same time... !?) earns
  3185.      you an "FOPEN stack overflow" error which aborts your script.  But since
  3186.      it's really DOS that is handling the file I/O, you 'can' run into a
  3187.      problem opening a file before ten files are open.  You are also limited
  3188.      to the number of DOS file handles the USER has set up in the CONFIG.SYS
  3189.      "FILES=" statement.  If you ever wondered what this statement was for...
  3190.      now you know.  As soon as DOS runs out of file handles, it prevents ANY
  3191.      program, system-wide, from opening more files.  FILES= determines the
  3192.      total number of files that may be open on the system at the same time;
  3193.      and the monitor, keyboard, and other devices use up some of these DOS
  3194.      file handles before you even begin to run a program.  [Your script does
  3195.      not use up a file handle though, since Icom loads scripts into memory,
  3196.      then FCLOSEs the script file.]
  3197.  
  3198.      If you ran a program prior to your script (a multitasker, etc) which has
  3199.      opened all the files DOS is set up to handle (FILES=)... you won't be
  3200.      able to FOPEN any files in your scripts.  FOPEN sets the $ERRORLEVEL
  3201.      System Variable to 2 if no file handles are available, and if that
  3202.      happens you can print a message to the user asking for an increase in the
  3203.      FILES= of the CONFIG.SYS file:
  3204.  
  3205.       fopen fh "TEST.DAT"
  3206.       IF $ERRORLEVEL = 2
  3207.        print "Unable to open file TEST.DAT due to a lack of file handles."
  3208.        pause "Please increase the FILES= statement in your CONFIG.SYS
  3209.      file...."
  3210.       ENDIF
  3211.  
  3212.  
  3213.  
  3214.  
  3215.      Intellicomm v2.01              SCRTUTOR.DOC                             52
  3216.      
  3217.      
  3218.  
  3219.      Various other problems can also occur when you FOPEN a file.  The most
  3220.      common is an invalid drive, path or filename (file not found) and in this
  3221.      case, $ERRORLEVEL is set to 1 by FOPEN.  If you attempt to open a "read
  3222.      only" file in write mode, FOPEN sets $ERRORLEVEL to 3 (and prevents any
  3223.      attempted writing to the file, since the file simply will not be opened
  3224.      and you won't have a valid file handle).  Thus, it's always wise to check
  3225.      $ERRORLEVEL after an FOPEN to see whether the file was successfully
  3226.      opened or not:
  3227.  
  3228.       FOPEN "test.dat" "r"
  3229.       if $ERRORLEVEL <> 0  ;$ERRORLEVEL = 0 if successful, <> is NOT equal to
  3230.        msgwind "Can't find/open TEST.DAT"
  3231.        if $ERRORLEVEL = 2 msgwind "Increase FILES= in your CONFIG.SYS"
  3232.        exit
  3233.       endif
  3234.  
  3235.      The error above would most likely be due to the fact that TEST.DAT didn't
  3236.      exist in the current DOS directory, but it could also mean that DOS is
  3237.      simply out of file handles and that the user must increase the FILES=
  3238.      statement in the CONFIG.SYS file.
  3239.  
  3240.      NOTE 3: FOPEN allocates a memory buffer for file input/output, and only
  3241.      writes to disk if/when the buffer fills up, or if FCLOSE or FFLUSH is
  3242.      called.  FFLUSH immediately writes all data from the memory buffer to
  3243.      disk... unless a disk cache is in use.  Disk cache write-ahead buffers
  3244.      intercept calls to write to disk and do it in their own time... and
  3245.      there's nothing you can do to prevent that, other than turning off the
  3246.      write-ahead buffer of the disk cache by reloading it with the proper
  3247.      command line switch.
  3248.  
  3249.      'Buffering' data in this manner makes the disk read/writes more
  3250.      effecient.  On reads, FGETS (or even FGETC to get a single character)
  3251.      will initially read in 512 bytes of the file to an internal buffer.  When
  3252.      you call FGETS/FGETC again it simply gets the data from the memory buffer
  3253.      instead of going to the disk again, which is much faster (the disk can't
  3254.      read less than 512 bytes [one sector] anyway).  If a file was written to
  3255.      (FPUTS, FPUTC, etc), by calling FCLOSE you cause any data in the write
  3256.      buffer to be written to disk.  I.e. FFLUSH is performed automatically
  3257.      when you FCLOSE the file.  In either read or write mode, you also free up
  3258.      the memory that is used for the read/write buffer when you call FCLOSE.  
  3259.  
  3260.      Though the script processor will automatically FCLOSE any files you left
  3261.      open when your script finishes, you should burn it into your brain now to
  3262.      *always* call FCLOSE.  When you write your scripts enter the FCLOSE while
  3263.      you're thinking about it:
  3264.  
  3265.       FOPEN f1 "\temp\myfile.txt" "w"
  3266.       FCLOSE f1
  3267.  
  3268.      Then go back and fill in the FGETS or FPUTS command(s) *between* the
  3269.      FOPEN and FCLOSE, just to make sure you don't omit it (this technique
  3270.      also works well with IF/ENDIF, WHILE/ENDWHILE, etc).  There are
  3271.      consequences in failing to FCLOSE an open file...  If you attempt to
  3272.      DELETE a file that is currently open, you can cause the computer to lock
  3273.  
  3274.  
  3275.  
  3276.  
  3277.      Intellicomm v2.01              SCRTUTOR.DOC                             53
  3278.      
  3279.      
  3280.  
  3281.      up, or can cause an "exception 13" (which requires a re-boot) if the
  3282.      script is running on a 386 processor or better.  So always FCLOSE a file
  3283.      as soon as you're done with it, to avoid such problems, and also to free
  3284.      up the memory buffer FOPEN allocates for file buffering... and the file
  3285.      handle DOS is using to keep track of the open file.
  3286.  
  3287.      YET ANOTHER NOTE:  File access is limited to the script from which the
  3288.      file was FOPENed.  You cannot FOPEN a file in one script, call another
  3289.      script with the SCRIPT command, and then attempt to access the same open
  3290.      file in the second script, using the same file handle (even if you use
  3291.      the GlobalStr array to store the file handle).  If you must access the
  3292.      same file data in two or more scripts you must FCLOSE the file before
  3293.      calling the second script and FOPEN it again in the called script.
  3294.  
  3295.      5.3  Testing for End-of-File  
  3296.  
  3297.      If FGETS is successful (it was able to read data from the file) it sets
  3298.      $ERRORLEVEL to 0.  When you reach the end of the file, FGETS will set
  3299.      $ERRORLEVEL to 1.  To read an entire file, you'd do it from a WHILE loop,
  3300.      testing $ERRORLEVEL in the loop:
  3301.  
  3302.       WHILE 1              ;enter an endless loop (until a BREAK is found)
  3303.        fgets s f1
  3304.        if $ERRORLEVEL <> 0 BREAK  ;if $errorlevel is not equal to 0
  3305.        print s
  3306.       ENDWHILE
  3307.  
  3308.      5.4  How to store settings on-disk
  3309.  
  3310.      If your script needs some sort of "main setup" data similar to
  3311.      Intellicomm's main setup or BIF information, you can use the File I/O
  3312.      commands to permanently store the settings.  How you do this is really up
  3313.      to you, and there is no "fixed" way of storing data on-disk.  If you had
  3314.      two "Yes/No" settings, you could store them on-disk like this:
  3315.  
  3316.       variable setting1 "Yes"
  3317.       variable setting2 "No"
  3318.       variable mydatafile $HOME_DIR "MYSCRIPT.INI"  ;C:\ICOM\MYSCRIPT.INI
  3319.       variable f
  3320.  
  3321.        ;here you could prompt the user for the Yes/No settings and store
  3322.        ; the result in 'setting1' and 'setting2'.
  3323.  
  3324.        ;later, to permanently store the settings...
  3325.  
  3326.       FOPEN f mydatafile "w"      ;create or overwrite MYSCRIPT.INI
  3327.       FPUTS f setting1            ;writes "Yes" (no quotes) to MYSCRIPT.INI
  3328.       FPUTS f setting2            ;writes "No" (no quotes) to MYSCRIPT.INI
  3329.       FCLOSE f
  3330.  
  3331.        ;each time your script started you could get the settings easily
  3332.  
  3333.       FOPEN f mydatafile "r"      ;open for reading
  3334.       if $errorlevel = 0          ;opened okay?
  3335.  
  3336.  
  3337.  
  3338.  
  3339.      Intellicomm v2.01              SCRTUTOR.DOC                             54
  3340.      
  3341.      
  3342.  
  3343.        FGETS setting1 f           ;store Yes/No in setting1
  3344.        FGETS setting2 f           ;store Yes/No in setting2
  3345.        FCLOSE f
  3346.       endif
  3347.        
  3348.        ;and finally, later in your script when you want to test a setting
  3349.  
  3350.       if setting1 = "Yes"
  3351.        ;do something if yes
  3352.       else
  3353.        ;do something else if not
  3354.       endif
  3355.  
  3356.      You needn't store the words "Yes" and "No" though, and storing numbers
  3357.      works just as well.  Zero (0) is a standard way of saying "No" (or FALSE)
  3358.      in computer programs, while non-zero is a standard way of saying "Yes"
  3359.      (or TRUE).  Thus you could substitute "Yes" and "No" above with 1 and 0,
  3360.      and save disk space (maybe... disks allocate space in large chunks and
  3361.      often it makes no difference whether a file has 1 byte or 1,000 bytes --
  3362.      the same space must be allocated regardless) and speed up your script a
  3363.      bit since numeric comparisons are faster than text comparisons:
  3364.  
  3365.       if setting1 <> 0     ;not equal to zero means "Yes"
  3366.        ;do something if yes
  3367.       else                 ;else (zero) means "No"
  3368.        ;do something else if zero (no)
  3369.       endif
  3370.  
  3371.      If you have multiple conditions, and not just Yes/No, just invent your
  3372.      own system where 0 means one thing, 1 means another, 2 means another,
  3373.      etc.  
  3374.      The format of the information you store in your data files is totally up
  3375.      to you, and it's half the fun of designing your own programs.
  3376.  
  3377.      5.5  Moving the File Pointer (Advanced Use Only)
  3378.  
  3379.      To move the 'file pointer' of an open file (the thing that keeps track of
  3380.      where FGETS will read from the file, and where FPUTS will write to next)
  3381.      you can either FCLOSE and FOPEN the file again, which starts you back at
  3382.      the beginning (or at the end if you open for "a"ppending), or use the
  3383.      FSEEK command to move the pointer to a specific position without closing
  3384.      the file.  FTELL is FSEEK's companion, and it tells you where (at what
  3385.      byte number in the file) the pointer currently is, if you need to know.
  3386.  
  3387.      FSEEK seeks to an absolute byte in the file (byte 0 being the first
  3388.      character in the file), INCLUDING all the carriage returns and line feeds
  3389.      in the count.  The only time it's of use is either when you know the
  3390.      exact byte count to the data you need (you've designed the data file
  3391.      yourself and have counted how many bytes there are to the position you
  3392.      desire, and accounted for all the CR/LF's), or when you use the STRPAD
  3393.      command with all your data before FPUTSing to the file, so that each line
  3394.      (or 'record' ... it might be a group of lines) is the same length.  If
  3395.      all lines in the file are the same size, you can then just MULtiply by
  3396.      the line/record length (plus the CR/LF), and FSEEK to the beginning of an
  3397.  
  3398.  
  3399.  
  3400.  
  3401.      Intellicomm v2.01              SCRTUTOR.DOC                             55
  3402.      
  3403.      
  3404.  
  3405.      exact line/record in the file.
  3406.  
  3407.      The best way to understand this is to look at the file in the same way
  3408.      the file I/O routines do.  They don't see a file line-by-line, they see
  3409.      it as a single 'stream' of characters:
  3410.  
  3411.                   1         2         3
  3412.         01234567890123456789012345678901  <-- Numeric Ruler for reference
  3413.      only.
  3414.         Line 1||Line 2||Line 3||Line 4||  <-- Data in the file
  3415.  
  3416.      (The || above denote the CR/LF at the end of each line, the numeric ruler
  3417.      denotes the positions of each character in the file.)  So, looking at the
  3418.      numeric ruler above, to FGETS line 1 you have to FSEEK to position 0.  To
  3419.      FGETS line 2, you have to FSEEK to position 8, line 3 is at position 16,
  3420.      and line 4 is at position 24.  All are multiples of 8, since each line is
  3421.      8 characters long, counting the CR/LF at the end of each line.
  3422.  
  3423.      To get any line out of the file above, you just DECrement the line you
  3424.      want by one, then multiply by 8.  If you want line 1, you multiply 0 by 8
  3425.      (0 x 8 = 0), if you want line 4 you multiply 3 by 8 (3 x 8 = 24). 
  3426.      Decrement the line number, then multiply by the line length.  Of course,
  3427.      this only works if all lines are the same length... which is why
  3428.      databases force you to define the length of each item before you store
  3429.      any data in the file.  By keeping each data item a specific length, it's
  3430.      easy to locate a single piece of information out of the middle of a file.
  3431.  
  3432.      For an illustration, let's assume you were storing a list of names and
  3433.      you wanted later to be able to seek to the fifth name, or the tenth name,
  3434.      etc., on request.  If you pad each name with spaces before you write it
  3435.      to disk, so that each line of the file is exactly 32 bytes long (30 for
  3436.      the name, 2 for the CR/LF), you can later get any name easily:
  3437.  
  3438.       variable name 
  3439.       variable f
  3440.  
  3441.       FOPEN f "C:\MYDIR\NAMES.DAT" "a"  ;open for "a"ppending (add to)
  3442.       printnc "Enter a name: " 
  3443.       gets name 30
  3444.       strpad name " " 30    ;pad the right side with spaces to ensure 30
  3445.                             ; characters ... STRPADL pads on the left side
  3446.       FPUTS f name          ;write the data, followed by CR/LF
  3447.       FCLOSE f
  3448.  
  3449.      You could then retrieve any line from the file by decrementing the line
  3450.      (record) you want, multiplying by the line length (record length), then
  3451.      FSEEKing to that position prior to calling FGETS.
  3452.  
  3453.        variable linenum
  3454.        variable bytecount
  3455.        variable name
  3456.        variable size
  3457.  
  3458.        printnc "Which name (record number) do you want? "
  3459.  
  3460.  
  3461.  
  3462.  
  3463.      Intellicomm v2.01              SCRTUTOR.DOC                             56
  3464.      
  3465.      
  3466.  
  3467.        gets linenum 5              ;allow 5 characters for input (a number)
  3468.        dec linenum                 ;linenum = linenum - 1
  3469.        mul bytecount linenum 32    ;bytecount = linenum x 32 (32 = line len).
  3470.  
  3471.         ;now 'bytecount' holds the absolute byte count to the beginning of
  3472.         ; the line.  If the user entered 1, we'd have decremented to 0,
  3473.         ; multiplied by 32, and ended up with 0 (32 x 0 = 0, the first byte of
  3474.         ; the file which would also be the start of the first line).  If the
  3475.         ; user entered 2, we'd decrement to 1, multiply by 32, and end up with
  3476.         ; 32 (32 x 1 = 32, the position of the SECOND line), and so forth.
  3477.  
  3478.        FILESIZE size "C:\MYDIR\NAMES.DAT"
  3479.  
  3480.         ;FILESIZE gets the size of a given file on disk and stores it
  3481.         ; in a variable
  3482.  
  3483.        if size < bytecount         ;file size less than bytecount?
  3484.         print "No such record."
  3485.         return
  3486.        endif
  3487.  
  3488.        FOPEN f "C:\MYDIR\NAMES.DAT" "r"  ;open for "r"eading
  3489.        FSEEK f bytecount 0           ;seek to the bytecount obtained above
  3490.        FGETS name f                  ;get the line at bytecount
  3491.        STRTRIM name                  ;trim off the trailing spaces
  3492.        print "Here is the name you requested:"
  3493.        print name
  3494.        FCLOSE f
  3495.        return
  3496.  
  3497.      The 0 following 'bytecount' in the FSEEK above specifies where in the
  3498.      file you want to seek FROM.  0 means to seek from the BEGINNING of the
  3499.      file, which is what we want in this case.  If 1 was specified after
  3500.      'bytecount' instead of 0, FSEEK would seek ahead 'bytecount' bytes from
  3501.      the CURRENT position of the file pointer (which would still work, since
  3502.      the file had just been opened, and thus the 'current' position was the
  3503.      beginning of the file).  If 2 was specified FSEEK would seek ahead from
  3504.      the END of the file.  It's legal to seek past the end of the file, but
  3505.      you end up with garbage in the file from the original end-of-file to the
  3506.      position you seek to.  An easy way to GET to the end of the file,
  3507.      actually, is to use
  3508.      FSEEK fhandle 0 2 (seek 0 bytes from the end of the file... it just moves
  3509.      the pointer to the end and leaves it there).
  3510.  
  3511.      You can also specify negative numbers in FSEEK to seek X number of bytes
  3512.      BACKWARDS from the end of the file, or from the current position.
  3513.  
  3514.        FSEEK f -500 2
  3515.  
  3516.      The FSEEK above seeks 500 bytes back from the END of the file.
  3517.  
  3518.        FSEEK f -32 1
  3519.  
  3520.      The above would seeks 32 bytes back from the CURRENT position.  You
  3521.  
  3522.  
  3523.  
  3524.  
  3525.      Intellicomm v2.01              SCRTUTOR.DOC                             57
  3526.      
  3527.      
  3528.  
  3529.      cannot seek past the beginning though.  If you attempt to, the file
  3530.      pointer will stop at the beginning of the file.
  3531.  
  3532.      Now, before we conclude the introduction and get to the more advanced
  3533.      techniques, we might as well mention the only file I/O command we haven't
  3534.      mentioned as yet:  FPUTSNC.  By now you should be quite clear on the fact
  3535.      that FPUTS writes CR/LF characters to terminate the line after the data
  3536.      you specify.  In most cases this is what you'll want, but in some cases
  3537.      you might want to write data to the file WITHOUT putting a CR/LF after
  3538.      it.  When this is the case, use FPUTSNC (NC meaning 'N'o 'C'arriage
  3539.      Return).  It simply writes the data you specify, and does not terminate
  3540.      the line with CR/LF.
  3541.  
  3542.      One more little tidbit: If you have to (or want to) write control
  3543.      characters, such as your own CR/LF's to a file, just look up the control
  3544.      character in the "ASCII Codes" online help line in Icom (available from
  3545.      the help index and the "Script Language" index).  Control characters are
  3546.      specified by preceding the character with a caret; CR is ^M (Ctrl-M) LF
  3547.      is ^J (Ctrl-J), etc.  To write them (or any other control character) to a
  3548.      file:
  3549.  
  3550.       FPUTS f "Write this, then a blank line.^M^J"
  3551.       FPUTS f "Now write this."
  3552.  
  3553.      After executing the above, you'd end up with this in the file:
  3554.  
  3555.      Write this, then a blank line.
  3556.  
  3557.      Now write this.
  3558.  
  3559.      The ^M^J terminate the first line, FPUTS adds its own ^M^J, and the
  3560.      result is a blank line.  You could accomplish the same thing with this:
  3561.  
  3562.       FPUTS f "Write this, then a blank line."
  3563.       FPUTS f ""                                ;write nothing, then ^M^J
  3564.       FPUTS f "Now write this."
  3565.  
  3566.      More details (and examples) on using FOPEN, FCLOSE, FGETC, FGETS, FPUTC,
  3567.      FPUTS, FPUTSNC, FSEEK, and FFLUSH can be found in the Detailed Command
  3568.      Summaries in SCRIPT.DOC when you need to refresh your memory.  It's too
  3569.      bad we don't have hard drives and file I/O routines built into our
  3570.      brains....
  3571.  
  3572.      5.6  Opening a File for Reading AND Writing (Advanced use only)
  3573.  
  3574.      By adding a plus sign (+) to the file FOPEN mode you are allowed to both
  3575.      read from (FGET) AND write to (FPUT) a file without closing it and re-
  3576.      opening it.  Examples:
  3577.  
  3578.       FOPEN f "MYFILE.DAT" "r+" ;open MYFILE.DAT for read/write (file must
  3579.                                 ; exist)
  3580.       FOPEN f "MYFILE.DAT" "w+" ;create MYFILE.DAT, allow reading and writing
  3581.       FOPEN f "MYFILE.DAT  "a+" ;create or append to MYFILE.DAT, allow reading
  3582.                                 ; and writing
  3583.  
  3584.  
  3585.  
  3586.  
  3587.      Intellicomm v2.01              SCRTUTOR.DOC                             58
  3588.      
  3589.      
  3590.  
  3591.      Opening a file for both reading and writing is an advanced technique that
  3592.      is not recommended until you have some experience with file I/O.  Unless
  3593.      you totally understand the 'file pointer' concept and FSEEK command,
  3594.      you'll end up writing data all over the place in the file, possibly
  3595.      overwriting useful data: Though you CANNOT overwrite data in other files
  3596.      no matter where you FSEEK to, unless there's something wrong with your
  3597.      disk.  If you FSEEK past the end of the file, DOS simply thinks you're
  3598.      trying to add to the file, and it looks for FREE disk space to write any
  3599.      new data (and if it doesn't find any, it doesn't write any data and the
  3600.      FPUTS will fail).  DOS will *never* use the disk space that another file
  3601.      is using, unless the other file was previously deleted, or unless your
  3602.      disk or disk drive is malfunctioning (in which case you're going to lose
  3603.      data anyway, whenever anything else writes to the disk).
  3604.        
  3605.      In read/write mode, the file pointer keeps track of both where the file
  3606.      will be read from AND written to next.  Since you'll almost never want
  3607.      data written at the point where the last read (FGETS/FGETC) left off, as
  3608.      a safeguard you must call FSEEK before you switch from reading to writing
  3609.      (from FGETS/FGETC to FPUTS/FPUTC) or vice versa.  If you start writing to
  3610.      the file, then want to switch to reading, you must also call FSEEK or the
  3611.      read(s) will fail, and vice versa if you switch from writing to reading.
  3612.  
  3613.      Normally, you will read several lines out of the file, then go to another
  3614.      position in the file (FSEEK) and write data elsewhere (or vice versa...
  3615.      keep this "vice versa" business in mind so I don't have to say it every
  3616.      time.  <grin>).  
  3617.  
  3618.      For example, you may wish to open a file for "r+" which opens it for read
  3619.      write (as opposed to "w+" which destroys the file's contents if it
  3620.      exists) and update a specific record in the file by FSEEKing to it, then
  3621.      FPUTSing over the old data (remembering to pad the item with spaces so
  3622.      that it overwrites ALL of the existing data in the file... more on this
  3623.      in a second).
  3624.  
  3625.      If you truly do wish to switch from read to write (the vice versa is
  3626.      still in play), WITHOUT moving the file pointer just use 'FSEEK f 0 1'
  3627.      (seek zero bytes from the current position... or leave the pointer where
  3628.      it is).  Here's an example of reading/writing with a single FOPEN:
  3629.  
  3630.       variable s
  3631.       variable f
  3632.  
  3633.       FOPEN f "\TEMP\TEST.DAT" "w+"   ;create TEST.DAT, allow reading/writing
  3634.  
  3635.       FPUTS f "Line 1"
  3636.       FPUTS f "Line 2"
  3637.       FPUTS f "Line 3"
  3638.       
  3639.       FSEEK f 0 0      ;seek 0 bytes from the beginning (1st byte in the file)
  3640.  
  3641.       FGETS s f
  3642.       print s          ;prints Line 1
  3643.       FGETS s f   
  3644.       print s          ;prints Line 2
  3645.  
  3646.  
  3647.  
  3648.  
  3649.      Intellicomm v2.01              SCRTUTOR.DOC                             59
  3650.      
  3651.      
  3652.  
  3653.       FGETS s f
  3654.       print s          ;prints Line 3
  3655.  
  3656.       FSEEK f 8 0      ;seek to 8 bytes from the beginning (start of Line 2)
  3657.       FPUTS f "Item 2" ;overwrites 'Line 2' with 'Item 2'.
  3658.       FCLOSE f
  3659.  
  3660.      If you FPUTS a line that is LONGER than the previous line in the file
  3661.      (e.g. FPUTS f "This is line 2") then you'd overwrite the CR/LF at the end
  3662.      of the previous 'Line 2' and can overwrite the beginning of 'Line 3' as
  3663.      well.  If you write a line that is SHORTER than the existing line, then
  3664.      some of the old data remains intact.  If we used:
  3665.  
  3666.       FSEEK f 8 0       ;seek to start of line 2
  3667.       FPUTS f "2"       ;write a 2 at the beginning of line 2
  3668.       FCLOSE f
  3669.  
  3670.      If we did this instead where we overwrote "Line 2" with "Item 2" above,
  3671.      we'd end up with "2||e 2" in the data file... (where || denote the CR/LF
  3672.      written by FPUTS) since it didn't overwrite the entire line.  The "e 2"
  3673.      after the CR/LF is the remainder of the old "Line 2".
  3674.  
  3675.      It works no differently than using Typeover mode in your text editor or
  3676.      word processor.  Think of the file as a SINGLE line of characters, and
  3677.      imagine what would happen to that line if you loaded it into your Editor,
  3678.      moved the cursor to a specific position (FSEEK), turned on Typeover mode
  3679.      and started typing.  That's what FPUTS is doing when you FSEEK to a
  3680.      specific position and start writing.  There is no way to 'insert' data
  3681.      into an existing file on-disk (though you can pretend you did... more on
  3682.      that in a second), anymore than you can 'insert' data on your video tapes
  3683.      or cassette tapes without overwriting what was there previously.  Again,
  3684.      if you STRPAD your data before writing it, you'll always have a few
  3685.      blanks at the end of the line to store longer items later.  And if you
  3686.      STRPAD shorter lines, you won't end up with the remainder of the existing
  3687.      (longer) data as was illustrated above.
  3688.  
  3689.      5.7  Upating an Old Data File
  3690.  
  3691.      The only way to change the existing structure (line length) of a text
  3692.      file is to FOPEN the existing file for reading, read each line, pad it to
  3693.      a longer length, then write the data to another file (similar must be
  3694.      done to add new lines between existing ones):
  3695.  
  3696.       variable datfile $HOME_DIR "TEST.DAT"  ;C:\ICOM\TEST.DAT
  3697.       variable tmpfile $HOME_DIR "TEST.$$$"  ;C:\ICOM\TEST.$$$
  3698.       variable dat                           ;for file handles
  3699.       variable tmp
  3700.       variable s                             ;for file data
  3701.       
  3702.       FOPEN dat datfile "r"       ;open TEST.DAT for reading
  3703.       FOPEN tmp tmpfile "w"       ;create/overwrite TEST.$$$
  3704.       if $errorlevel <> 0 exit    ;exit if error opening either file
  3705.  
  3706.       while 1                     ;endless loop (until BREAK)
  3707.  
  3708.  
  3709.  
  3710.  
  3711.      Intellicomm v2.01              SCRTUTOR.DOC                             60
  3712.      
  3713.      
  3714.  
  3715.        FGETS s dat                ;read in a line from TEST.DAT
  3716.        if $errorlevel <> 0 break  ;end of file? (no data in 's' if so)
  3717.        strpad s " " 50            ;pad it to the new length
  3718.        FPUTS tmp s                ;write the longer line in TEST.$$$
  3719.        if $errorlevel <> 0        ;uh oh... we ran out of disk space
  3720.         fclose tmp                ; close 'em up, and avoid that
  3721.         fclose dat                ; DELETE datfile below like the plague
  3722.         delete tmpfile            ;we can't use this anymore, lose it
  3723.         print "Disk full.  Aborting."
  3724.         exit
  3725.        endif
  3726.       endwhile
  3727.       
  3728.       fclose tmp
  3729.       fclose dat
  3730.  
  3731.       delete datfile              ;delete TEST.DAT
  3732.       rename tmpfile datfile      ;rename TEST.$$$ to TEST.DAT
  3733.  
  3734.      So, if you ever wondered what those .$$$ files were that you found lying
  3735.      around on your disk, now you know.  A program either forgot to clean up
  3736.      its temporary file (I hope it wasn't Intellicomm), or perhaps the power
  3737.      went out or the machine hung before it got a chance to delete it.  The
  3738.      extension .$$$ is often used to avoid overwriting useful files.  You
  3739.      'could' use the filename "ICOM.EXE" for your temporary file, but TEST.$$$
  3740.      (or anything .$$$) is probably safer.
  3741.  
  3742.      Experimentation is the best way to get a feel for file I/O.  Create a
  3743.      dummy text file to play around with, and run a few FGETS/FPUTS tests on
  3744.      the file to see what happens (load the text file into the editor and look
  3745.      at it after each test).  "Seeing is believing" and you really have to
  3746.      experience file I/O first-hand to get a good feel for it.
  3747.  
  3748.      REMEMBER:
  3749.  
  3750.      o Always either perform a CHDIR to get to the proper drive/directory, or
  3751.        specify the full D:\PATH\FILENAME.EXT in FOPEN when you use it. 
  3752.        Otherwise the CURRENT DIRECTORY is assumed, which could be painful if
  3753.        you FOPEN for "w"riting, and are using a common filename... and an
  3754.        important file of the same name exists in the current directory.
  3755.  
  3756.      o Never attempt to DELETE or RENAME an open file.
  3757.  
  3758.      o Make sure the file pointer is at the proper position before you FPUTS
  3759.        (or FPUTSNC, FPUTC) to overwrite old data in an existing data file. 
  3760.        You can only do this if you know the exact format of the data file
  3761.        (i.e. if you created it yourself or otherwise have a reliable way of
  3762.        knowing) and use FSEEK prior to the disk write to move the file pointer
  3763.        to the proper position.  Once you FPUTS you cannot UNFPUTS, and an
  3764.        FFLUSH will only ensure that the data is written to disk faster. 
  3765.        Further, if you overwrite existing data, the NEW data must be of the
  3766.        same length as the old data (or must be padded with spaces), or you
  3767.        will either overwrite the beginning of the next line, or will end up
  3768.        with a portion of the old data after the new data.
  3769.  
  3770.  
  3771.  
  3772.  
  3773.      Intellicomm v2.01              SCRTUTOR.DOC                             61
  3774.      
  3775.      
  3776.  
  3777.      o FPUTS writes a Carriage Return/Line Feed after data, and FGETS uses
  3778.        this CR/LF to determine when to stop reading data from the file (it
  3779.        reads one line, and stops when it hits the LF).  You must take the
  3780.        CR/LF into account when calculating byte counts with FSEEK.
  3781.  
  3782.      o Always FCLOSE a file as soon as you're finished reading/writing to it. 
  3783.  
  3784.      o Pat yourself on the back.  These same concepts (though in slightly
  3785.        different syntaxes) are used for file I/O in all computer programs, and
  3786.        all programming languages.  If you got through all of the above, and if
  3787.        you actually practice it and succeed, you could consider yourself a
  3788.        fairly able computer programmer.
  3789.  
  3790.  
  3791.  
  3792.  
  3793.      Intellicomm v2.01              SCRTUTOR.DOC                             62
  3794.      
  3795.      
  3796.  
  3797.             6.  INTRODUCTION TO DATABASE COMMANDS (FILE TAGGER CATALOGS)
  3798.  
  3799.  
  3800.      This section introduces you basic database concepts and will help you to
  3801.      make effective use of the script database or "File Tagger Catalog
  3802.      oriented" commands.  The material is somewhat advanced (though not
  3803.      terribly so), and you should have a basic grasp of scripts such as
  3804.      variables, the ASSIGN command, WHILE loops, etc., before you tackle this
  3805.      section.
  3806.  
  3807.      6.1  Why would I want to use the catalog-oriented commands?
  3808.  
  3809.      The main purpose of the catalog-oriented commands is to allow you to
  3810.      perform customized maintenance on your Tagger catalogs.  Using job Custom
  3811.      Commands, or the PREJOB.SCR, PREDOWN.SCR or POSTFILE.SCR scripts (see
  3812.      "Automation in Detail" in the Icom online help for details on these
  3813.      scripts) and executing a script prior to a Call to a BBS, you could scan
  3814.      a given Tagger catalog and automatically Tag (or Untag) certain files, or
  3815.      set Transfer Days (the day of the week on which to transfer the file)
  3816.      based on file criteria such as the filesize.  Or, you could add up the
  3817.      total number of bytes of all Tagged files and change the tag status of
  3818.      certain files to a special tag of your own which would allow you to
  3819.      temporarily untag the file and re-tag it later after the job completed,
  3820.      and so forth.  Or you could modify the description (or any other
  3821.      attributes) of files after downloads by adding to POSTFILE.SCR.  In
  3822.      short, by getting a handle on the File Tagger-oriented commands, you'll
  3823.      gain absolute and total control over your File Tagger catalogs, in every
  3824.      imaginable way, in most every aspect of use.
  3825.  
  3826.      Many requests have come in for specialized File Tagger catalog handling
  3827.      that really wouldn't benefit the majority of Intellicomm users, but
  3828.      certainly would be helpful to those people who made the requests.  Using
  3829.      the catalog-oriented commands, you can handle almost any specialized
  3830.      catalog-oriented task you can dream up -- and you can handle it exactly
  3831.      as YOU need it done, without being forced to use "pre-fabricated"
  3832.      ICOM.EXE routines which might not do exactly what you want.
  3833.  
  3834.      6.2  What is a Database?
  3835.  
  3836.      Databases (and File Tagger Catalogs which are dBASE-compatible
  3837.      databases), in the context we are interested in here, are files that hold
  3838.      information on-disk in a specific format.  They are made up of simple
  3839.      units called "fields" and "records":
  3840.  
  3841.      "Field 1, Record 1"   |
  3842.      "Field 2, Record 1"   |---- RECORD 1
  3843.      "Field 3, Record 1"   |
  3844.  
  3845.      "Field 1, Record 2"   |
  3846.      "Field 2, Record 2"   |---- RECORD 2
  3847.      "Field 3, Record 2"   |
  3848.  
  3849.      ...etc.  Each record contains a given number of fields, and each field
  3850.      holds a specific type of information, of a specific length.  In File
  3851.  
  3852.  
  3853.  
  3854.  
  3855.      Intellicomm v2.01              SCRTUTOR.DOC                             63
  3856.      
  3857.      
  3858.  
  3859.      Tagger catalogs, the "fields" are the filename, file date, import date,
  3860.      description, etc., and each "record" holds information about ONE file
  3861.      that exists on a BBS (if accessing the NEWFILES catalog, which holds BBS
  3862.      new files listings) or on your disk (if accessing the FILELIST catalog,
  3863.      which keeps track of the files Icom auto-downloads to let you re-upload
  3864.      them to other BBS's).
  3865.  
  3866.      The importance of keeping each field a specific length, as opposed to
  3867.      storing data all different lengths, is that it makes it very easy (and
  3868.      fast) to access any given record in the database.  Since each field is a
  3869.      fixed size (regardless of the actual data being stored in the field),
  3870.      each record is the same size and thus the position of any given record in
  3871.      the file is easy to obtain.  If the combined length of all fields in all
  3872.      records is 50 bytes, and we want record #10, we simply multiply 50 by 10
  3873.      to find the position of the record, in the database file.
  3874.  
  3875.      If the fields/records were NOT all the same size, it would be difficult
  3876.      (and slow) to pull a given record out of the database, since we'd have to
  3877.      start at the beginning, and 'count' records (perhaps using a special
  3878.      character between each record so we knew where each record ended) until
  3879.      we got to the one we wanted.
  3880.  
  3881.      dBASE-compatible databases (and File Tagger Catalogs) use the file
  3882.      extension .DBF (e.g. NEWFILES.DBF, FILELIST.DBF, etc), and each record in
  3883.      the file has a number starting at record #1, up to a maximum of (about)
  3884.      record #2 billion.  To get at any of the records, we (or something else,
  3885.      such as the indexes discussed below) must first know the record number.
  3886.  
  3887.      In File Tagger catalogs, record #1 is reserved for a "header" record,
  3888.      which is where the Tagger saves information such as the bookmark
  3889.      position, the current View Date of the catalog, the sort order and
  3890.      direction as set by the user, etc.  The header record is no different
  3891.      than any of the other records (it has the exact same fields... it has
  3892.      to), other than the fact that the File Tagger reserves it for its own
  3893.      use, to store information.  You cannot access record #1 directly, though
  3894.      you can update most of the information in the header (such as the catalog
  3895.      sort order, bookmark position, current view date, etc) with special
  3896.      script commands which are outlined later in this section.
  3897.  
  3898.      The rest of the records in the File Tagger catalogs hold information
  3899.      about files, such as the filename, date, size, whether the file is Tagged
  3900.      for transfer or not, etc.
  3901.  
  3902.      6.3  Indexes
  3903.  
  3904.      Database index (.NDX) files are special files which allow easy sorting of
  3905.      one particular .DBF database in a specific way.  When new records are
  3906.      added to a database (.DBF), they are not 'inserted' into the existing
  3907.      record structure, but rather are simply added (appended) to the END of
  3908.      the .DBF file.  If you have 10 records in your database, and add one, the
  3909.      new record becomes record #12 (12 because record #1 is used as a header,
  3910.      as mentioned above.  The header (record #1) plus 10 existing records
  3911.      (records 2-11), plus the new record #12).
  3912.  
  3913.  
  3914.  
  3915.  
  3916.      Intellicomm v2.01              SCRTUTOR.DOC                             64
  3917.      
  3918.      
  3919.  
  3920.      However, as mentioned above, to get a specific data record from the
  3921.      database, we must have the record number.  Now suppose you want to get
  3922.      all the Tagged records out of a Tagger Catalog that has 5,000 records in
  3923.      it.  We already know that the .DBF itself doesn't sort the records in any
  3924.      specific way, and simply appends new records to the end ... so do we have
  3925.      to read record #2, check for a Tag, then read record #3, check for a Tag,
  3926.      all the way up to 5,000 records?  Thankfully, no, since it would be very
  3927.      time-consuming (and disk-punishing) to do so.  This where the .NDX files
  3928.      come into play.
  3929.  
  3930.      When an .NDX is in use the .DBF file is NOT accessed in its natural
  3931.      record order.  When you access the 'first' record in the database, you
  3932.      might get record #5,000 while the 'last' record might be record #25. 
  3933.      I.e. the indexes give us the proper .DBF record numbers needed to display
  3934.      (or otherwise manipulate) the database according to a specific sort
  3935.      order.  When an NDX is in use, the database routines jump all over the
  3936.      database, perhaps grabbing record #5, then record #50, then record #12,
  3937.      etc., though this is mostly invisible to you.
  3938.  
  3939.      How the NDX's actually accomplish this sorting is not important:  The
  3940.      important thing to understand is that when an index is in use, the
  3941.      'first' record in the database is not necessarily record #1 (or #2 in our
  3942.      case, since record #1 is reserved for the header).  The 'first' record is
  3943.      simply the record that happens to sort first (alphabetically,
  3944.      chronologically, or otherwise, according to how the index is defined),
  3945.      given a specific sort order, as compared to all the other records in the
  3946.      database.  The indexes do all the sorting, and it takes zero work on your
  3947.      part.  It is important to understand the CONCEPTS behind indexes, since
  3948.      sometimes you WILL be involved with the actual database record numbers,
  3949.      and it could be confusing to see record #5,000 coming 'first', then
  3950.      record #10 coming 'next', etc., were you not aware of how the .NDX(s) and
  3951.      .DBF work together.
  3952.  
  3953.      6.4  Using File Tagger Indexes
  3954.  
  3955.      The File Tagger maintains three index (.NDX) files per File Tagger
  3956.      catalog, and stores them all in the same directory as the .DBF itself
  3957.      (the $DBF_DIR System Variable can be used to access the proper
  3958.      directory).  The indexes use the same base name as the catalog
  3959.      ("NEWFILES" is the "base" name of the NEWFILES.DBF database), but replace
  3960.      or add a new letter at the end of the base name.  Below we'll use the
  3961.      base name NEWFILES to illustrate the filename of each index (you don't
  3962.      "have" to know the .NDX filename except when you want to delete a
  3963.      catalog, or rebuild a damaged index):
  3964.  
  3965.       1. "Tag Status/Location" (NEWFILET.NDX ... replaces the "S" at the end
  3966.          of NEWFILES with a "T" since the filename is already 8 letters; "T"
  3967.          for "Tag Status"), used to easily get all the Tagged (or Noted, or
  3968.          Untagged) files for a specific BBS.
  3969.  
  3970.       2. "Catalog Date/Filesize (NEWFILEC.NDX ... "C" for Catalog Date), the
  3971.          oldest records to the newest records, the smallest to the largest.
  3972.          This index makes for quick and easy purging (deleting) of older
  3973.          records.  The "Catalog Date" is the date on which the record was
  3974.  
  3975.  
  3976.  
  3977.  
  3978.      Intellicomm v2.01              SCRTUTOR.DOC                             65
  3979.      
  3980.      
  3981.  
  3982.          added (imported to) to the database.
  3983.  
  3984.       3. "Filename/File Date" (NEWFILEF.NDX ... "F" for Filename) all
  3985.          filenames in the database, in alphabetical order.  This index makes
  3986.          for quick duplicate checking (so we needn't search filenames of all
  3987.          the records in the catalog when importing) and other filename
  3988.          searches.
  3989.  
  3990.      The script COPEN command ("C"atalog OPEN; all catalog-oriented commands
  3991.      begin with "C" for Catalog) opens the .DBF (database), all three
  3992.      associated indexes, and the .DBT (standard dBASE "memo" file which holds
  3993.      the extended descriptions of files).  If any or all of the .NDX files are
  3994.      missing, COPEN automatically builds new ones.  And thus a handy way to
  3995.      build new indexes, if the need ever arises, is to simply use the DELETE
  3996.      command to delete the one or more .NDX files (after the catalog is
  3997.      CLOSED; do not delete open NDX files), then call COPEN and it will build
  3998.      new ones based on contents of the .DBF file.
  3999.  
  4000.      IMPORTANT: When an existing record is deleted from the database
  4001.      (permanently in a CPACK, not when it's just flagged as "Deleted"), or a
  4002.      new record is added, all three .NDX files are *automatically* updated or
  4003.      rebuilt entirely to insert the new record data in the proper place
  4004.      according to each index sort order.  You will never work with an .NDX
  4005.      file directly ... it's all taken care of automatically by the File Tagger
  4006.      (and the Tagger-oriented script commands), as new records are added, and
  4007.      old records are deleted.  I.e. you never have to "maintain" an .NDX from
  4008.      your script.  You simply "use" them (by setting a sort order with the
  4009.      CSETSORT command), and let Icom take care of the boring maintenance
  4010.      details.
  4011.  
  4012.      6.5  How this all applies to Scripts
  4013.  
  4014.      Accessing a File Tagger catalog is much the same as accessing a regular
  4015.      text file with the File I/O script commands:
  4016.  
  4017.      1. Open the catalog with COPEN.
  4018.      2. Set the sort order (.NDX) if necessary with CSETSORT.  Note that all
  4019.         three of a catalog's NDX files are 'opened' when you perform a COPEN,
  4020.         and CSETSORT simply switches from one index to another.
  4021.      3. Use CGETREC to read the first record.  The next call to CGETREC gets
  4022.         the next record, etc, according to the sort order (index) you set with
  4023.         CSETSORT.  Again, the 'first' record changes from sort order to sort
  4024.         order, and most likely will NOT be record #2 (the first valid record
  4025.         in the database, due to the header) in the .DBF file.  After you CGET
  4026.         a RECord ('get' meaning load it from disk into memory) you can modify
  4027.         it and write it back to the database (CPUTREC) or can display it, Tag
  4028.         it, Note it, Untag it, etc.  *Until* you CGETREC a record from the
  4029.         database you can't do a thing with it: the record must be loaded from
  4030.         disk into memory before you can access or manipulate it.
  4031.      4. Close the catalog (when finished) with CCLOSE.
  4032.  
  4033.      When you use CGETREC to load a record from the database (again, 'load'
  4034.      meaning that it is read from the database on-disk and loaded into memory
  4035.      where you can work with it), the record is split up into the "fields"
  4036.  
  4037.  
  4038.  
  4039.  
  4040.      Intellicomm v2.01              SCRTUTOR.DOC                             66
  4041.      
  4042.      
  4043.  
  4044.      mentioned at the outset.  Each field goes into a different script System
  4045.      Variable as listed below.  These fields listed below are exactly the
  4046.      fields you see when you "Edit" a record from within the File Tagger:
  4047.  
  4048.      $CTAG_FLD    The tag status of the file (Tagged, Noted, Untagged).  With
  4049.                   inventive use of this field (if need be), you can set your
  4050.                   own custom tags which will be meaningful to your script, but
  4051.                   will be meaningless to Intellicomm itself when transferring
  4052.                   files.  $CTAG_FLD field normally holds a 'T' if the file is
  4053.                   Tagged, an 'N' if the file is Noted, and a 'U' if the file
  4054.                   is untagged.  Icom ignores any letters from 'U' to the end
  4055.                   of the alphabet, leaving you with several possibilities for
  4056.                   "custom" tags which you might use to, say, automatically
  4057.                   Untag a very large file, marking the $CTAG_FLD with the
  4058.                   letter 'Z'.  When Icom finishes transferring files (it will
  4059.                   ignore your custom 'Z' tags), you can then go through the
  4060.                   catalog looking for your 'Z' tags, and can then re-tag the
  4061.                   files with the regular 'T' for Tag.  You'll be able to
  4062.                   understand how you might accomplish this better after you
  4063.                   finish this chapter.
  4064.      $CDAY_FLD    The transfer day, if set by the user or by a script.  This
  4065.                   field can be compared against the $DOW (Day of Week) System
  4066.                   Variable to see if the file should be transferred 'today' or
  4067.                   not.  If $CDAY_FLD = "0" (Anyday, the default), the user
  4068.                   cares not on which day the file is transferred.  This one
  4069.                   can also be used to force Intellicomm to ignore a Tagged
  4070.                   file; Icom checks this field when transferring files, and
  4071.                   won't bother with it if $CDAY_FLD doesn't match $DOW (the
  4072.                   current day of the week).
  4073.      $CNAME_FLD   The FILENAME.EXT of the file.  No D:\PATH\ is ever stored in
  4074.                   this field, even in the FILELIST (upload) catalog.  Icom
  4075.                   keeps a list of Upload Directories (defined in the Icom main
  4076.                   setup on the "Filenames and Paths" screen; accessable from
  4077.                   scripts via the $UL_PATH item) and looks in those
  4078.                   directories to find files when uploading.  You do the same
  4079.                   with the LOCFILE (Locate File) script command.
  4080.      $CFDATE_FLD  The file (or archive) modification/creation date, in
  4081.                   standard dBASE date format: YYYYMMDD  [Year, Month, Day]
  4082.      $CSIZE_FLD   The size of the file.
  4083.      $CCDATE_FLD  The date that the record was added to the catalog, in
  4084.                   standard dBASE date format (the CATALOG DATE: this is what
  4085.                   the "View Date" uses to filter out older files, and the View
  4086.                   Date is still in effect when you access a catalog from a
  4087.                   script ... though you can change the View Date from your
  4088.                   script if need be).
  4089.      $CLOC_FLD    The BIF ID/filename (the BBS that has the file).  If you are
  4090.                   online when your script is accessing the Tagger Catalog you
  4091.                   can compare this field against the $BIF_NAME System Variable
  4092.                   to see if the file exists on the BBS Icom is currently
  4093.                   connected to.
  4094.      $CAREA_FLD   The BBS conference/forum the file is in (NEWAREA $CAREA_FLD
  4095.                   can be used if online to change to the proper BBS area;
  4096.                   assuming the BIF is set up for it with the proper "Area
  4097.                   Change" command on the BIF "File" screen).
  4098.  
  4099.  
  4100.  
  4101.  
  4102.      Intellicomm v2.01              SCRTUTOR.DOC                             67
  4103.      
  4104.      
  4105.  
  4106.      REMEMBER: CGETREC 'loads' a single catalog (.DBF) record from disk into
  4107.      memory (with each field from the record going into the variables listed
  4108.      above).  Thus you cannot (if you want anything valid) access the above
  4109.      variables above *until* you COPEN a catalog, and use CGETREC to load a
  4110.      record from disk.
  4111.  
  4112.      There are two exceptions to this:  During automated file transfers, and
  4113.      in the POSTFILE.SCR script (see the comments in POSTFILE.SCR included
  4114.      with Intellicomm).  During automated file transfers Intellicomm will have
  4115.      already performed a COPEN (and perhaps a CGETREC) on the files it's
  4116.      automatically transferring.  There are four places in the BIF where you
  4117.      can have a script called during automated file transfers (all are on the
  4118.      BIF "File" screen): the "Area Change" "Upload File[s]", "Download
  4119.      File[s]", and "Description [@SCRIPT]" slots.  By entering @SCRIPTNAME in
  4120.      any of these BIF slots, Icom will run a script instead of sending a
  4121.      single command (as is the case with all BIF responses).  The only place
  4122.      you really 'should' place a @SCRIPTNAME command during an automated file
  4123.      transfer, if necessary, is in the "Description [@SCRIPT]" command.  The
  4124.      purpose of this is to handle entry of the file description (on uploads)
  4125.      in tricky situations where the usual description entry routine can't
  4126.      handle.  If you call a script via this BIF slot, Intellicomm will already
  4127.      have performed a CGETREC, and the fields listed above (plus the
  4128.      description, outlined below) WILL contain valid values, without your
  4129.      opening the catalog with COPEN.  If you do use a script during automated
  4130.      file transfers, DO NOT close the catalog (CCLOSE), or set the sort order
  4131.      to the Tag Status/Location index and move the pointer (i.e. perform a
  4132.      CGETREC) or Icom will lose its place.
  4133.  
  4134.      If you change any of the variables above after a CGETREC, you do NOT
  4135.      modify the actual record in the database -- you modify only memory
  4136.      variables.  To modify a record permanently you must re-write the data
  4137.      back from memory to the disk using CPUTREC.  This is typical of file I/O
  4138.      on computers, and you almost never work with a disk file directly, in any
  4139.      computer program (unless writing your own version of DOS).  We "work"
  4140.      with the computer's memory (very fast), and use the disk (DOS file
  4141.      Input/Output; extremely slow in computer terms) only when permanent
  4142.      storage is required.
  4143.  
  4144.      You may notice above that the file DESCRIPTION isn't stored in a System
  4145.      Variable, and this because no script variable can hold more than 256
  4146.      characters of text in Intellicomm's script language; yet descriptions
  4147.      will often contain over 256 characters.  Thus, CGETREC loads the entire
  4148.      description into a large internal memory buffer and two script commands
  4149.      -- CGETDESC and CPUTDESC -- are used to get a single line of the
  4150.      description from this buffer, and load it into a variable where you can
  4151.      work with it one line at a time.
  4152.  
  4153.      Again, CPUTDESC does not modify the description on-disk in the catalog. 
  4154.      It simply affects the description (line by line) in an internal memory
  4155.      buffer.  So you can 'CGETDESC myvariable 1' to get description line 1,
  4156.      modify it, then 'CPUTDESC myvariable 1' to write the modified line 1 back
  4157.      to the memory buffer (the old line is stripped first, so if you CPUDESC a
  4158.      blank line, you remove the original description line).  To update a
  4159.      record (description included, as well as updating of the .NDX files) on-
  4160.  
  4161.  
  4162.  
  4163.  
  4164.      Intellicomm v2.01              SCRTUTOR.DOC                             68
  4165.      
  4166.      
  4167.  
  4168.      disk you must call CPUTREC.  
  4169.  
  4170.      One more note on descriptions: When loaded into the memory buffer by
  4171.      CGETREC, descriptions are formatted to 45 characters per line (wrapping
  4172.      words that don't fit on the 45 character line, in the same way as a word
  4173.      processor does).  After using CGETREC you can re-format the description
  4174.      to another line length by calling CFORMATDESC.  For example you wanted 40
  4175.      character description lines you would:
  4176.  
  4177.        CGETREC                  ;get the record (more on this in a second)
  4178.        CFORMATDESC 40           ;format to no more than 40 characters per line
  4179.        CGETDESC somevariable 1  ;put description line 1 (now 40 chars or less)
  4180.                                 ; into variable 'somevariable'
  4181.  
  4182.      Now before you get completely lost, it's time for an example you can sink
  4183.      your teeth into.  Let's display the NEWFILES catalog, sorted by Tag
  4184.      Status/Location.  Displaying a catalog isn't something you're likely to
  4185.      do with a script (the File Tagger can most likely do a better/faster job)
  4186.      but the concepts of cycling through the catalog records are the same
  4187.      whether you're displaying them or downloading files, or checking and
  4188.      modifying records, or doing anything else.  A good way to get practice is
  4189.      to go through a catalog DISPLAYING various things on the screen yourself,
  4190.      so you can get a feel for it.  Make sure you read the comments (;) below:
  4191.  
  4192.      variable key             ;first we need a few variables for use below
  4193.      variable tag
  4194.      variable name
  4195.      variable date
  4196.      variable desc
  4197.  
  4198.      wndopen "NEWFILES Catalog" 1 1 80 25 ;open a box to display in
  4199.      print " ^BFilename        Date                    Description^B"
  4200.      window 2 3 79 24                     ;so we don't overwrite the titles
  4201.  
  4202.      COPEN "NEWFILES"                     ;open the .DBF and its .NDX's 
  4203.  
  4204.       ;Next, set the sort order.  CSETSORT takes two parameters: the first
  4205.       ; is the sort order (-1 = unsorted, 1 = Tag Status/Location, 2 = Catalog
  4206.       ; Date/Filesize, 3 = Filename/File Date) and the second is the sort
  4207.       ; DIRECTION (0 [or nothing] = forward, 1 = reversed)
  4208.  
  4209.      CSETSORT 1     ;Tag Status/Location, FORWARD:  Noted records come first,
  4210.                     ; Tagged records come second, Untagged records come last.
  4211.                     ; If we reverse the sort order, Untagged records come
  4212.                     ; first, Tagged second, and Noted third.
  4213.  
  4214.       ;Note that if no parameters are specified after CSETSORT (or if you
  4215.       ; specify anything other than -1, 1, 2, or 3 as the sort order), the
  4216.       ; user is prompted to enter the sort order and direction (identical to
  4217.       ; when "Sort" is selected from within the File Tagger), which is a handy
  4218.       ; way to get user input when needed.  Note also that CSETSORT does NOT
  4219.       ; change the sort order as saved in the catalog itself (i.e. the order
  4220.       ; the user has set).  You must use CSAVESORT to save the sort order to
  4221.       ; the catalog header, if you want to keep the sort order 'permanently'.
  4222.  
  4223.  
  4224.  
  4225.  
  4226.      Intellicomm v2.01              SCRTUTOR.DOC                             69
  4227.      
  4228.      
  4229.  
  4230.       ;If you do not call CSETSORT after COPENing a catalog, it will remain
  4231.       ; sorted in the same manner as the user had it set up the last time it
  4232.       ; was viewed, which probably isn't what you'd want.  You can check the
  4233.       ; current sort order, if need be, by accessing the $CSORT_ORDER and
  4234.       ; $CSORT_DIR (direction) System Variables.  They contain the same values
  4235.       ; outlined in the CSETSORT parameters listed above.
  4236.  
  4237.      while 1                             ;enter an endless loop (until BREAK)
  4238.       CGETREC                            ;gets first (or next) record
  4239.       if $errorlevel <> 0 break          ;end loop at end of catalog
  4240.       if $CTAG_FLD = "T" assign tag "^P" ;T = Tagged (^P = > as in Tagger)
  4241.       if $CTAG_FLD = "N" assign tag "»"  ;N = Noted
  4242.       if $CTAG_FLD = "U" assign tag " "  ;U = Untagged
  4243.       assign name $CNAME_FLD             ;copy the filename into our variable
  4244.       strpad name " " 14                 ;pad filename with spaces to 14 chars
  4245.        ;as mentioned earlier, $CCDATE_FLD and $CFDATE_FLD are stored in
  4246.        ; standard dBASE date format YYYYMMDD.  We don't want to display the
  4247.        ; date like this, so we call CDATE2DATE to convert it to the usual
  4248.        ; date format/date separators the user has set up in the Icom main
  4249.        ; setup.
  4250.       CDATE2DATE date $CFDATE_FLD        ;the result is stored in 'date'
  4251.       CGETDESC desc 1                    ;get description line 1
  4252.       strblank desc assign desc "No description available"
  4253.       print "^B" tag "^B" name date "  " desc  ;print the data (^B is Bold)
  4254.      endwhile
  4255.  
  4256.      CCLOSE                              ;and close the catalog when done
  4257.      pause "^M^J^BPress a key..."
  4258.      wndclose
  4259.      return
  4260.  
  4261.      What happens above is that the commands between WHILE and ENDWHILE are
  4262.      executed over and over again, until the end of the catalog is found
  4263.      (CGETREC sets $ERRORLEVEL to 1 when it hits the end).  So CGETREC is
  4264.      called repeatedly and each record is displayed, until the end of the
  4265.      catalog is found.
  4266.  
  4267.      When COPEN or CSETSORT are called, the 'record pointer' that CGETREC uses
  4268.      to know which record to get from the database, is automatically set to
  4269.      the 'beginning' of the catalog (the 'beginning' according to the sort
  4270.      order).  After CGETREC gets the record and stores the data in the
  4271.      $CXXXX_FLD System Variables, it updates an internal record pointer (using
  4272.      the current .NDX) to point to the 'next' record, again, according to the
  4273.      current sort order.  So each call to CGETREC gets the next record,
  4274.      according to the current sort order.... it couldn't be simpler.
  4275.  
  4276.      You can use the CTELL command to find out which database record number
  4277.      CGETREC got, and if you used CTELL in the loop above and printed out the
  4278.      record numbers, you'd probably see that CGETREC was jumping all over the
  4279.      database getting perhaps record #5, then record #30, then record #10,
  4280.      etc.
  4281.  
  4282.      You don't 'have' to know the current record number except in one case:
  4283.      when CDELREC is used to delete a record.  For safety's sake, you must get
  4284.  
  4285.  
  4286.  
  4287.  
  4288.      Intellicomm v2.01              SCRTUTOR.DOC                             70
  4289.      
  4290.      
  4291.  
  4292.      (with CTELL) and specify a record number to delete when you use CDELREC. 
  4293.      With most other catalog-oriented script commands that take a record
  4294.      number (several do, though optionally), if you OMIT the record number,
  4295.      the 'current' record (the last record obtained with CGETREC) is assumed.
  4296.  
  4297.      6.6  The View Date
  4298.  
  4299.      As mentioned earlier, the View Date is still in effect when accessing a
  4300.      catalog from a script... which means that records with a $CCDATE_FLD
  4301.      (Catalog Date) *older* than the View Date ($VIEW_DATE) are filtered out. 
  4302.      I.e. CGETREC ignores these older records.  The one exception to this is
  4303.      if you use CSETSORT -1 (no sort order).  In this case, the View Date is
  4304.      ignored, and database records are accessed in their raw order (as they
  4305.      were added to the .DBF), and CGETREC gets all records regardless of their
  4306.      Catalog Date.
  4307.  
  4308.      You can check and/or modify the View Date from your scripts by accessing
  4309.      the $VIEW_DATE System Variable.  If you modify $VIEW_DATE, the date must
  4310.      be stored in standard dBASE format: YYYYMMDD (YearMonthDay).  Examples:
  4311.  
  4312.       ASSIGN $VIEW_DATE "19900101" ;January 1st, 1990.  Setting this View Date
  4313.                                    ; will ensure that ALL existing records
  4314.                                    ; are found by CGETREC (and CSEEK,
  4315.                                    ; discussed below).  Intellicomm was not
  4316.                                    ; released by that date, so it's impossible
  4317.                                    ; for a record to have a catalog date older
  4318.                                    ; than 01/01/90.
  4319.       variable dbase_date
  4320.       DATE2CDATE dbase_date $DATE  ;convert today's date to dBASE format
  4321.       ASSIGN $VIEW_DATE dbase_date ;only records imported today are found by
  4322.                                    ; CGETREC (and CSEEK), if an index is in
  4323.                                    ; use
  4324.  
  4325.      Note that neither ASSIGN $VIEW_DATE example above would change the View
  4326.      Date as saved in the catalog itself.  If you wish to save View Date
  4327.      changes to the catalog header (i.e. so it will take effect the next time
  4328.      the user views the catalog, or the next time you open it with COPEN), use
  4329.      CSAVEVDATE.
  4330.  
  4331.      Note also that the File Tagger itself automatically updates the View Date
  4332.      to the current date ('today') when it imports BBS new files listings, so
  4333.      that the user only sees the new files that were imported.  This is the
  4334.      date that $VIEW_DATE will be set to when you first COPEN a catalog: the
  4335.      date of the last import.
  4336.  
  4337.      The 'Auto View Date Update' on imports is a feature that can be turned
  4338.      off in the Icom main setup though (Tagger Settings), and you can also
  4339.      check that setting or temporarily shut it off in your script by accessing
  4340.      the "*afdate" Main Setup Variable (apologies for the 'f' ... The View
  4341.      Date was originally named the Filter Date, and 'af' stands for 'auto
  4342.      filter' date.  Converting the tag in the ICOM.INI file from 'afdate' to
  4343.      'avdate' wasn't worth the trouble).  SAVEINI re-saves the Main Setup data
  4344.      to disk if you wish to permanently change this or any other Main Setup
  4345.      Variable from a script.  See the Main Variable summary in SCRIPT.DOC for
  4346.  
  4347.  
  4348.  
  4349.  
  4350.      Intellicomm v2.01              SCRTUTOR.DOC                             71
  4351.      
  4352.      
  4353.  
  4354.      details on this or any other Main Setup Variable.
  4355.  
  4356.      6.7  Getting Around in a Catalog
  4357.  
  4358.      You may have noticed in the main example above that while there are a
  4359.      couple of twists as far as fields and sorting goes, access to the
  4360.      database was sequential (one record after the other), much like reading a
  4361.      text file with FGETS.  And just as you can move the file 'pointer' around
  4362.      with FSEEK when reading text files so that FGETS reads at a different
  4363.      position in the file, CSEEK allows you to move the 'record pointer' of
  4364.      the database so that CGETREC gets one or more records out of sequence. 
  4365.      It works in much the same way as FSEEK (don't worry if you've never used
  4366.      FSEEK; it isn't mandatory for this discussion), except that you never
  4367.      need worry about the specific file positions, since the database
  4368.      structure does all the work for you.
  4369.  
  4370.      CSEEK takes two parameters: the first is "the number of records FROM
  4371.      whence" and the second is whence (0 = from the beginning of the catalog,
  4372.      1 = from the present position, 2 = from the end of the catalog, 3 = from
  4373.      anywhere; it seeks to an absolute record number).  Examples:
  4374.  
  4375.       CSEEK 0 0   ;seek 0 records from the beginning (take it from the top)
  4376.       CSEEK 10 0  ;seek to the tenth record from the beginning
  4377.       CSEEK 1 1   ;seek ahead (from current position) by one record
  4378.       CSEEK 10 1  ;seek ahead (from current position) by ten records
  4379.       CSEEK -10 2 ;seek ten records back from the end
  4380.       CSEEK 100 3 ;locate record #100 in the index (100 must be a valid rec#)
  4381.  
  4382.      As mentioned earlier, CSETSORT automatically puts you back at the top of
  4383.      the catalog (an automatic CSEEK 0 0 is performed after CSETSORT).  If you
  4384.      want to change the sort order with CSETSORT, but DON'T want to lose your
  4385.      current position in the catalog, first GET your current record number
  4386.      with CTELL, then either use mode 3 of CSEEK (seek to an absolute record
  4387.      number) or specify that record number with CGETREC to re-load it, and to
  4388.      seek back to that record in the index:
  4389.  
  4390.       variable cur_rec     ;use any variable to store the record number
  4391.  
  4392.       CTELL cur_rec        ;stores current record number in 'cur_rec'
  4393.       CSETSORT 2 1         ;set a new sort order
  4394.       CSEEK cur_rec 3      ;seek back to the previous record number
  4395.       CGETREC              ;gets record 'cur_rec' as stored by CTELL
  4396.  
  4397.        ;alternatively, you can do this
  4398.  
  4399.       CTELL cur_rec        ;stores current record number in 'cur_rec'
  4400.       CSETSORT 2 1         ;set a new sort order
  4401.       CGETREC cur_rec      ;"CSEEK cur_rec 3" implied before CGETREC
  4402.  
  4403.      It may seem like there's a valid need for this (and perhaps you'll find
  4404.      one... though the only place this sort of thing is used in Icom is when
  4405.      DISPLAYING the catalog to the user, and s/he changes the sort order... so
  4406.      we keep the pointer on the same record).  But in most cases, once you
  4407.      change the sort order you might as well start back at the beginning,
  4408.  
  4409.  
  4410.  
  4411.  
  4412.      Intellicomm v2.01              SCRTUTOR.DOC                             72
  4413.      
  4414.      
  4415.  
  4416.      since the 'current' record (as reported by CTELL before the change in
  4417.      sort order), although it still has the same record number, will now be in
  4418.      a completely different position in the database, RELATIVE to where it was
  4419.      before the sort order was changed.  If it was the 20th record previously
  4420.      (in relation to the 'top' of the catalog according to the last sort
  4421.      order), it might be the 50th record from the 'top' after a change in the
  4422.      sort order, or may the the last record in the database, or the first,
  4423.      etc.  Further, the "next" and "previous" records before and after
  4424.      'cur_rec' will not be the same as they would have been, had the sort
  4425.      order not been changed.  Even the first and last records in the database
  4426.      will be different.  [Speaking in relation to other records, according to
  4427.      the sort order.  The database record numbers always remain the same, but
  4428.      the record numbers are mostly irrelevant when an index is in use.]  Thus
  4429.      there's little use in going back to the same position after a re-sort,
  4430.      since it's not the 'same' position at all, and none of the other records
  4431.      that were around the current record previously will remain the same
  4432.      either.
  4433.  
  4434.      If you're confused, you can see this quite clearly by entering the File
  4435.      Tagger and selecting "Sort" (in a catalog that contains a screenful of
  4436.      records or more) to change the sort order.  The 'pointer' remains in the
  4437.      same position, but all the records around the pointer change... and the
  4438.      position of the current record in relation to the 'top' of the catalog
  4439.      (as evidenced by the little box in the scrollbar, on the right border of
  4440.      the Tagger) changes as well.  It's a whole new ball game after a change
  4441.      in the sort order, and thus normally you'll only perform *one* CSETSORT,
  4442.      just after the COPEN.  In such a case, you'll also probably want to start
  4443.      at the top of the catalog, which is what CSETSORT automatically does.
  4444.  
  4445.      6.8  Getting the Total Number of Records
  4446.  
  4447.      Before using CSEEK, you can get the total number of records in the
  4448.      database if necessary by checking the $CTOTAL System Variable.  And, if
  4449.      an index is in use (if CSETSORT -1 is used, no index is in use) $CVTOTAL
  4450.      tells you how many records are visible according to the current View Date
  4451.      ($VIEW_DATE).  In most cases, if using a sort order, $CTOTAL will not be
  4452.      the same as $CVTOTAL, since the View Date is normally set to filter out
  4453.      older records.  Example:
  4454.  
  4455.       variable num_filtered
  4456.  
  4457.        ;Below is a 'SUBtract': num_filtered = $CTOTAL - $CVTOTAL
  4458.        ; This gives us the number of records that are currently being filtered
  4459.        ; out (or zero if none).
  4460.  
  4461.       SUB num_filtered $CTOTAL $CVTOTAL
  4462.  
  4463.       print num_filtered " records are hidden due to the View Date."
  4464.  
  4465.      The above displays the number of records that are currently being
  4466.      filtered out due to the View Date.  Note that $CVTOTAL is calculated when
  4467.      you open (COPEN) a catalog, and is re-calculated whenever you change the
  4468.      $VIEW_DATE variable.
  4469.  
  4470.  
  4471.  
  4472.  
  4473.      Intellicomm v2.01              SCRTUTOR.DOC                             73
  4474.      
  4475.      
  4476.  
  4477.      6.9  The View Date and Tagged/Noted Files
  4478.  
  4479.      Tagged files are NEVER filtered out by the View Date, whether an index is
  4480.      in use or not.  And Noted files are not filtered out by default, but that
  4481.      can be changed by the user in the Icom Main Setup on the File Tagger
  4482.      Settings screen.  If "View Date Filters Noted?" is set to Yes in the Icom
  4483.      Main Setup, then the Noted files imported prior to the current View Date
  4484.      WILL be ignored (filtered out) by CGETREC and CSEEK, if an index is in
  4485.      use.  You can change this if need be by accessing the *fnote (filter
  4486.      noted) Main Setup Variable:
  4487.  
  4488.       ASSIGN *fnote 0   ;View Date doesn't filter out any Noted files
  4489.       ASSIGN *fnote 1   ;View Date does filter out (older) Noted files
  4490.  
  4491.      If you modify this or any other Main Setup Variable, you must make sure
  4492.      to SAVE the previous value, and restore it when your script ends... or it
  4493.      will remain that way until Intellicomm is exited/reloaded, or until a new
  4494.      main setup file is loaded (LOADINI, or a manual "Load" via the Icom main
  4495.      setup menu).  As with all variables, you are modifying memory locations
  4496.      and you do not change data on-disk when you modify a variable.  You must
  4497.      use SAVEINI to update the Icom Main Setup file on-disk.  See the Main
  4498.      Setup Variables section in SCRIPT.DOC for more details.
  4499.  
  4500.      There are many other catalog-related commands, including: CCLEARBUF
  4501.      (clears all the $XXX_FLD variables, and the file description memory
  4502.      buffer, perhaps to get ready to fill in a new record yourself before
  4503.      CADDREC), CDELREC, CEDITREC (same as "Edit" from the File Tagger; [PgUp]
  4504.      and [PgDn] can also be used to browse through the database), CEMPTY,
  4505.      CEXPORT, CFLUSH, CIMPORTNEW, CIMPORTTEXT, CNOTEREC, CPACK, CTAGREC and
  4506.      several others.  They all are quite simple to use, and most just perform
  4507.      tasks you normally carry out right from the Tagger, so none should
  4508.      require much explaining if you understand the Tagger, and the material
  4509.      above.  You can find all the necessary information, along with examples,
  4510.      in the Detailed Command Summaries in SCRIPT.DOC.  To see a quick summary
  4511.      of all the Catalog-oriented commands, see the "Script Commands at a
  4512.      Glance" secion in SCRIPT.DOC.
  4513.  
  4514.  
  4515.  
  4516.  
  4517.      Intellicomm v2.01              SCRTUTOR.DOC                             74
  4518.      
  4519.      
  4520.  
  4521.                            7.  USING THE SCRIPT DEBUGGER
  4522.  
  4523.  
  4524.      7.1  What are BUGS, and What is a DEBUGGER?
  4525.  
  4526.      What!  Bugs in MY script?!  No matter how hard you try, no matter how
  4527.      careful you are about writing your scripts, somewhere, sometime you're
  4528.      probably going to run into a problem that you simply can't figure out. 
  4529.      You'll look the script over and pull your hair out: everything will LOOK
  4530.      fine.  You'll check the manual; you'll check your commands again, you'll
  4531.      check the manual again ... and just before you're ready to throw your
  4532.      computer out the window you'll remember the Debugger!
  4533.  
  4534.      Debuggers aren't designed to find your programming errors for you:
  4535.      they're designed to slow your program down (or script, in this case), run
  4536.      it step-by-step, show you each command before it gets executed, and show
  4537.      you the results of each command (screen output, etc) after it is
  4538.      executed.  Sometimes it's the only way to pick up subtle errors... and
  4539.      subtle errors can sometimes create large problems.
  4540.  
  4541.      Bugs are not syntax errors such as misspelling a command/variable or the
  4542.      like: Icom will pick those up and abort the script, pointing the error
  4543.      out to you.  Bugs are logic errors, where you're perhaps meaning to see
  4544.      if something is less than or equal to a number... and you're instead
  4545.      (unintentionally) telling Icom to check whether the number is GREATER
  4546.      than or equal to the number.  Or you have two variables called X and Y,
  4547.      and you use Y when you meant to use X, and so forth.  These sorts of
  4548.      errors cannot be picked up by Icom's script processor (or any programming
  4549.      language for that matter), since it trusts that you know what you're
  4550.      doing... It doesn't second-guess you, and has no way of knowing whether
  4551.      you REALLY wanted to use X when you used Y, or wanted greater than (>)
  4552.      and used less than (<) by mistake.  This is where the debugger comes in.
  4553.  
  4554.      Here are some examples of the kinds of bugs you're likely to run into,
  4555.      that you can find with the debugger:
  4556.  
  4557.      1. Garbage In Garbage Out.  This means that if the data you're using is
  4558.         garbage (not valid) then the results you'll get will also be garbage. 
  4559.         It applies to anything that uses any sort of data (script command
  4560.         parameters and all script variables are 'data') to perform a function. 
  4561.         The debugger can help eliminate this problem by showing you the
  4562.         CONTENTS of variables (the data), before the script command acts upon
  4563.         the data.  A common mistake is to inadvertently change the contents of
  4564.         a variable somewhere else (in the same script; a subroutine perhaps)
  4565.         without realizing it.  You'll *think* that a certain variable is
  4566.         holding a certain value... but you'll have forgotten that the same
  4567.         variable is used elsewhere in the script, and is thus modified
  4568.         elsewhere.  By using the debugger you can follow the script step-by-
  4569.         step to find where your data is corrupted.
  4570.  
  4571.      2. Another common error is to forget to initialize one or more variables
  4572.         before entering a loop.  If you were using a variable called 'count',
  4573.         and you had previously been using 'count' for something and its value
  4574.         was now higher than 10, then this loop below would NOT execute at all:
  4575.  
  4576.  
  4577.  
  4578.  
  4579.      Intellicomm v2.01              SCRTUTOR.DOC                             75
  4580.      
  4581.      
  4582.  
  4583.          while count <= 10  ;while 'count' is less than or equal to 10
  4584.           ...
  4585.           inc count         ;increment count (count = count + 1)
  4586.          endwhile
  4587.       
  4588.         By using the debugger you'd see this on the bottom screen line before
  4589.         the WHILE command was executed, if 'count' had a value of 15:
  4590.  
  4591.          5: WHILE 15 <= 10
  4592.  
  4593.         The debugger pauses prior to executing each line and shows you the
  4594.         script line number it's about to execute (5 in the example above)
  4595.         followed by a colon and the command.  But instead of showing you the
  4596.         variable names it first REPLACES the variable names with the data that
  4597.         is stored in the variable.  Your mistake would then be obvious (15
  4598.         isn't less than or equal to 10), and you could abort the script and
  4599.         modify it so that 'count' was properly initialized to whatever it
  4600.         should be initialized to before entering the loop:
  4601.  
  4602.          assign count 1       ;this was missing... now the loop works fine
  4603.          while count <= 10
  4604.           ...
  4605.           inc count           ;increment count (count = count + 1)
  4606.          endwhile
  4607.  
  4608.      3. Variable mix-ups.  You think variable 'Y' is holding a certain value,
  4609.         but you're mistaken and actually variable 'X' has the value you
  4610.         wanted.  Using the debugger, with the values of variables displayed on
  4611.         the status line, you'll be able to pick up the mistake.
  4612.  
  4613.      4. Logic errors.  You're comparing two values, and either get the
  4614.         arguments mixed up left to right, or use the wrong operator in between
  4615.         (less than instead of greater than, etc).  If you're expecting an IF
  4616.         or WHILE comparison to be TRUE, and it turns out to be false and skips
  4617.         commands you didn't expect it to, then you'll know that the problem is
  4618.         in your IF or WHILE comparison and can take a closer look.  Often you
  4619.         can only pick this up by executing the script line-by-line in debug
  4620.         mode and watching closely.  With the script running at full tilt you
  4621.         might not even realize that the comparison had proven false, and that
  4622.         one or more script lines were skipped as a result.
  4623.  
  4624.      There are all sorts of tiny errors like this that can cause scripts (and
  4625.      computer programs in general) to malfunction.  If you ever wondered where
  4626.      program bugs come from... and thought it was due to shabby work, now you
  4627.      know different.  <grin>  The types of errors that cause script or program
  4628.      bugs are often so subtle that the only way to find them is to execute the
  4629.      program one line at a time... and even then you'll often have to watch
  4630.      carefully.
  4631.  
  4632.      7.2  Using the Debugger
  4633.  
  4634.      To activate the debugger while a script is EXECUTING simply press [Alt-Q]
  4635.      (the usual job/script 'Q'uit command), then select "Script DEBUG [Step-
  4636.      by-step]" or "Script DEBUG [Animate]" from the Alt-Q menu.  To turn
  4637.  
  4638.  
  4639.  
  4640.  
  4641.      Intellicomm v2.01              SCRTUTOR.DOC                             76
  4642.      
  4643.      
  4644.  
  4645.      debugging off, press [Alt-Q] and select "Script DEBUG [OFF]".
  4646.  
  4647.      In 'step-by-step' mode, the debugger displays each script line as
  4648.      outlined above, then waits for you to press the [Space] bar, [Enter] key,
  4649.      or left mouse button before it executes the line.  In 'animate' mode,
  4650.      each script line is displayed momentarily before it executes, running at
  4651.      about 2 lines per second (to quickly zero in on the general area of a
  4652.      problem, when you're not quite sure where to start looking).
  4653.  
  4654.      You can also turn step-by-step and animate mode on/off around lines of
  4655.      your script where you suspect a problem:
  4656.  
  4657.       DEBUG 1         ;turn step-by-step mode ON
  4658.       DEBUG 2         ;turn animate mode ON
  4659.       DEBUG 0         ;turn step-by-step or animate mode OFF
  4660.  
  4661.      This is how you'll normally turn debug mode on and off, by adding DEBUG
  4662.      commands to your script in and around lines where you suspect a problem.
  4663.      Pressing the [Alt-Q] key and selecting a debug mode manually might be
  4664.      difficult to time properly.
  4665.  
  4666.      When either debug mode is on, Icom will pause prior to executing each
  4667.      line and will show you the line it's about to execute (with all the
  4668.      relevant variables replaced to show the VALUE of the variable).  To see
  4669.      the script line in its original format (with the variable names instead
  4670.      of the contents of the variables), press and hold the [Alt] key.  When
  4671.      you release the [Alt] key the line will revert back to the original
  4672.      format, showing the value of the variables.  This can be helpful for
  4673.      cases where you get two variables mixed up, and you intended to use X,
  4674.      but you used Y by accident.  When you see the 'wrong' value displayed,
  4675.      hold down the [Alt] key to see the NAME of the variable you used.  You
  4676.      might have used the wrong variable by mistake.  The [Alt] key can also be
  4677.      useful for pausing animate mode temporarily.  Animate mode pauses for as
  4678.      long as you hold the [Alt] key down (and you can also press [Alt-Q]
  4679.      before releasing [Alt] to switch from animate mode to step-by-step mode).
  4680.  
  4681.      If the line is longer than can be displayed on the screen, use the
  4682.      [Left], [Right] cursor arrow keys (or mouse left/right motion) to scroll
  4683.      the line left/right.
  4684.  
  4685.      If you find a bug and wish to abort the script, again it's done via the
  4686.      [Alt-Q] menu by selecting "Abort Script Only".  To get a quick summary of
  4687.      all these keys, press the [F1] help key when in either debugging mode.
  4688.  
  4689.      NOTE 1: Script commands which permit OTHER commands to be executed if a
  4690.      certain condition is true (DIREXIST, EXIST, OFFLINE, ONLINE, etc) will
  4691.      show up on the debug display TWICE if the condition is true.  For
  4692.      example, with an OFFLINE command you'd see something like this on the
  4693.      debug display first:
  4694.  
  4695.          5: OFFLINE GOTO exit_script
  4696.       
  4697.      ...then, if the modem WAS offline (the condition was true), you'd see
  4698.      this on the debug display, before the specified command was executed:
  4699.  
  4700.  
  4701.  
  4702.  
  4703.      Intellicomm v2.01              SCRTUTOR.DOC                             77
  4704.      
  4705.      
  4706.  
  4707.          5: GOTO exit_script
  4708.  
  4709.      The same line number is displayed since the second command is on the same
  4710.      line.
  4711.  
  4712.      NOTE 2: If a command takes a parameter that will be changed as soon as
  4713.      you press the [Space] bar ('ADD z y x' for example would assign y + x to
  4714.      z immediately), then the debugger doesn't bother showing you the contents
  4715.      of the variable, and simply shows you the variable name.  It's more
  4716.      useful (and easier to follow) to be able to see which variable you're
  4717.      assigning to, rather than looking at something like this:
  4718.  
  4719.          7: ADD 0 123 456   ;where 5 would be the CONTENTS of a variable
  4720.  
  4721.      (Where '0' just happened to be the contents of 'z' BEFORE the ADD command
  4722.      was executed.)  In these cases, the debugger displays:
  4723.  
  4724.          7: ADD myvariable 123 456
  4725.  
  4726.      This applies only to certain commands where it may prove confusing to
  4727.      display the contents of the variable rather than the variable name, as
  4728.      with ADD above, where you might get the impression that the ADD had
  4729.      already taken effect and the WRONG value had been stored (which would not
  4730.      be the case, since the command has not executed as yet).  There are some
  4731.      cases, such as with ADDSLASH where a variable IS going to be changed, but
  4732.      the debugger does display the contents of the variable:
  4733.  
  4734.          8: ADDSLASH "C:\SOMEDIR"
  4735.  
  4736.      is more useful than:
  4737.  
  4738.          8: ADDSLASH mydirectory
  4739.  
  4740.      would be.  If you want to check the contents of such variables AFTER the
  4741.      command executes, and you don't have any lines below that use the
  4742.      variable, use the DEBUG command as outlined below. 
  4743.  
  4744.      7.3  Checking the Contents of a Single Variable
  4745.  
  4746.      To have the debugger simply display the contents of a single variable to
  4747.      the screen and wait for you to press [Space] or [Enter], specify the
  4748.      variable name after the DEBUG command:
  4749.  
  4750.       variable myvariable  ;define a variable called 'myvariable'
  4751.        ...
  4752.       GETS myvariable 10   ;get keyboard input to 'myvariable'
  4753.       DEBUG myvariable     ;pause and display the contents of 'myvariable'
  4754.        ...
  4755.       capture "NEWCAP.CAP" ;open a new capture file
  4756.       DEBUG $CAP_FNAME     ;display the full '$CAP_NAME' (drive/path, etc).
  4757.  
  4758.      The two DEBUG commands above would might display something like this:
  4759.  
  4760.         10: DEBUG "User Input"
  4761.  
  4762.  
  4763.  
  4764.  
  4765.      Intellicomm v2.01              SCRTUTOR.DOC                             78
  4766.      
  4767.      
  4768.  
  4769.         20: DEBUG "C:\ICOM\CAP\NEWCAP.CAP"
  4770.  
  4771.      This allows you to see the contents of a variable without actually
  4772.      'doing' anything.  You don't have to be in DEBUG mode (i.e. by pressing
  4773.      [Alt-Q]) to use this command.  You can place them anywhere in your
  4774.      script, wherever you suspect a problem, and Icom will switch to debug
  4775.      mode temporarily to display the contents of the specified variable.
  4776.  
  4777.      If you ARE in debug mode and a 'DEBUG variable' command is found, the
  4778.      command is simply displayed as any other command would be.  If in animate
  4779.      mode, this use of DEBUG also causes the debugger to pause and wait for
  4780.      [Space] or [Enter] before continuing in animate mode.
  4781.  
  4782.      Again, press and hold the [Alt] key to see the original script line (the
  4783.      variable name instead of the contents of the variable).  After you've
  4784.      checked the contents of the variable, press [Space] or [Enter] (or the
  4785.      left mouse button) to continue running the script at full speed (or to
  4786.      continue in Animate mode if you were in Animate mode previously), or
  4787.      again use the [Alt-Q] menu to either abort the script, or go into step-
  4788.      by-step or animate mode, etc.
  4789.  
  4790.      7.4  Debug Hotkeys
  4791.  
  4792.      When debug mode is active, most of the Icom hotkeys are disabled.  You
  4793.      cannot, for example, press [Alt-M] to switch to the Main Menu.  You can,
  4794.      however, use [Alt-A] to enter the editor, [Alt-J] to 'Jump' to a DOS
  4795.      shell, [Alt-N] (user-defined Hotkey 1), [Alt-O] (user-defined hotkey 2),
  4796.      and [Alt-V] to run your external archiver.  When you finish with the
  4797.      called task, you'll be returned to the debug display exactly as it was
  4798.      before you pressed the hotkey.
  4799.  
  4800.      IMPORTANT: If you use [Alt-A] to run the editor and change the script
  4801.      Icom is running, the changes will not take effect until you abort and re-
  4802.      start the script.  Icom loads scripts into memory, and changing the
  4803.      script file (on-disk) in the editor doesn't affect the script in memory
  4804.      that Icom is running.
  4805.